Merge branch 'main' into js/shared-dataflow

This commit is contained in:
Asger F
2024-06-25 11:48:41 +02:00
2477 changed files with 100491 additions and 79725 deletions

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.1.16
No user-facing changes.
## 0.1.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,21 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
### Minor Analysis Improvements
* The data flow library now adds intermediate nodes when data flows out of a function via a parameter, in order to make path explanations easier to follow. The intermediate nodes have the same location as the underlying parameter, but must be accessed via `PathNode.asParameterReturnNode` instead of `PathNode.asNode`.
## 0.2.7
No user-facing changes.
## 0.2.6
### Major Analysis Improvements

View File

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

View File

@@ -0,0 +1,9 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
### Minor Analysis Improvements
* The data flow library now adds intermediate nodes when data flows out of a function via a parameter, in order to make path explanations easier to follow. The intermediate nodes have the same location as the underlying parameter, but must be accessed via `PathNode.asParameterReturnNode` instead of `PathNode.asNode`.

View File

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

View File

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

View File

@@ -72,12 +72,24 @@ signature module InputSig<LocationSig Location> {
/** Gets a textual representation of this element. */
string toString();
/** Gets the location of this call. */
Location getLocation();
DataFlowCallable getEnclosingCallable();
/** Gets a best-effort total ordering. */
int totalorder();
}
class DataFlowCallable {
/** Gets a textual representation of this element. */
string toString();
/** Gets the location of this callable. */
Location getLocation();
/** Gets a best-effort total ordering. */
int totalorder();
}
class ReturnKind {
@@ -130,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);
/**
@@ -251,10 +262,18 @@ signature module InputSig<LocationSig Location> {
*/
predicate expectsContent(Node n, ContentSet c);
/** A set of `Node`s in a `DataFlowCallable`. */
class NodeRegion {
/** Holds if this region contains `n`. */
predicate contains(Node n);
int totalOrder();
}
/**
* Holds if the node `n` is unreachable when the call context is `call`.
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
*/
predicate isUnreachableInCall(Node n, DataFlowCall call);
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call);
default int accessPathLimit() { result = 5 }
@@ -609,7 +628,7 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = ""
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
@@ -631,7 +650,7 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = ""
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}

View File

@@ -80,7 +80,7 @@ module TaintFlowMake<
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = ""
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
@@ -106,7 +106,7 @@ module TaintFlowMake<
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = ""
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}

View File

@@ -163,6 +163,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
TNodeNormal(Node n) or
TNodeImplicitRead(Node n, boolean hasRead) {
Config::allowImplicitRead(n, _) and hasRead = [false, true]
} or
TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) {
paramReturnNode(_, p, scope, _)
}
private class NodeEx extends TNodeEx {
@@ -170,13 +173,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
result = this.asNode().toString()
or
exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
or
result = this.asParamReturnNode().toString() + " [Return]"
}
Node asNode() { this = TNodeNormal(result) }
predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) }
Node projectToNode() {
this = TNodeNormal(result) or
this = TNodeImplicitRead(result, _) or
this = TParamReturnNode(result, _)
}
pragma[nomagic]
private DataFlowCallable getEnclosingCallable0() {
@@ -189,7 +200,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
}
pragma[nomagic]
private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
private DataFlowType getDataFlowType0() {
nodeDataFlowType(this.asNode(), result)
or
nodeDataFlowType(this.asParamReturnNode(), result)
}
pragma[inline]
DataFlowType getDataFlowType() {
@@ -215,12 +230,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ParameterPosition getPosition() { this.isParameterOf(_, result) }
}
/**
* A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a synthesized node for flow out via a parameter.
*/
private class RetNodeEx extends NodeEx {
RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
private ReturnPosition pos;
ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
RetNodeEx() {
pos = getValueReturnPosition(this.asNode()) or
pos = getParamReturnPosition(_, this.asParamReturnNode())
}
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
ReturnPosition getReturnPosition() { result = pos }
ReturnKindExt getKind() { result = pos.getKind() }
}
private predicate inBarrier(NodeEx node) {
@@ -324,9 +348,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
not stateBarrier(node2, state2)
}
pragma[nomagic]
bindingset[n, cc]
pragma[inline_late]
private predicate isUnreachableInCall1(NodeEx n, LocalCallContextSpecificCall cc) {
isUnreachableInCallCached(n.asNode(), cc.getCall())
cc.unreachable(n.asNode())
}
/**
@@ -341,12 +366,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
or
exists(Node n |
Config::allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1) and
model = ""
)
or
exists(Node n1, Node n2, SndLevelScopeOption scope |
node1.asNode() = n1 and
node2 = TParamReturnNode(n2, scope) and
paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2),
pragma[only_bind_into](scope), _) and
model = ""
)
}
/**
@@ -362,7 +394,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
or
exists(Node n |
Config::allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2) and
@@ -497,10 +528,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
}
private predicate sourceCallCtx(CallContext cc) {
if hasSourceCallCtx() then cc instanceof CallContextSomeCall else cc instanceof CallContextAny
}
private predicate hasSinkCallCtx() {
exists(FlowFeature feature | feature = Config::getAFeature() |
feature instanceof FeatureHasSinkCallContext or
@@ -1113,26 +1140,17 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
result = getAdditionalFlowIntoCallNodeTerm(arg.projectToNode(), p.projectToNode())
}
private module SndLevelScopeOption = Option<DataFlowSecondLevelScope>;
private class SndLevelScopeOption = SndLevelScopeOption::Option;
pragma[nomagic]
private SndLevelScopeOption getScope(RetNodeEx ret) {
result = SndLevelScopeOption::some(getSecondLevelScopeCached(ret.asNode()))
or
result instanceof SndLevelScopeOption::None and
not exists(getSecondLevelScopeCached(ret.asNode()))
}
pragma[nomagic]
private predicate returnCallEdge1(
DataFlowCallable c, SndLevelScopeOption scope, DataFlowCall call, NodeEx out
) {
exists(RetNodeEx ret |
flowOutOfCallNodeCand1(call, ret, _, out) and
c = ret.getEnclosingCallable() and
scope = getScope(ret)
c = ret.getEnclosingCallable()
|
scope = getSecondLevelScopeCached(ret.asNode())
or
ret = TParamReturnNode(_, scope)
)
}
@@ -1352,6 +1370,18 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
CcCall ccSomeCall();
/*
* The following `instanceof` predicates are necessary for proper
* caching, since we're able to cache predicates, but not the underlying
* types.
*/
predicate instanceofCc(Cc cc);
predicate instanceofCcCall(CcCall cc);
predicate instanceofCcNoCall(CcNoCall cc);
class LocalCc;
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CcCall ctx);
@@ -1362,15 +1392,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
bindingset[call, c]
CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c);
DataFlowCallable viableImplCallContextReducedReverse(DataFlowCall call, CcNoCall ctx);
DataFlowCall viableImplCallContextReducedReverse(DataFlowCallable c, CcNoCall ctx);
predicate viableImplNotCallContextReducedReverse(CcNoCall ctx);
bindingset[call, c]
CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call);
bindingset[node, cc]
LocalCc getLocalCc(NodeEx node, Cc cc);
bindingset[cc]
LocalCc getLocalCc(Cc cc);
bindingset[node1, state1]
bindingset[node2, state2]
@@ -1414,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.
*
@@ -1435,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]
@@ -1459,7 +1522,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
exists(NodeEx mid, FlowState state0, Typ t0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argT, argAp, t0, ap, apa) and
localCc = getLocalCc(mid, cc)
localCc = getLocalCc(cc)
|
localStep(mid, state0, node, state, true, _, localCc) and
t = t0
@@ -1596,7 +1659,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ApOption argAp, Typ t, Ap ap, boolean emptyAp, ApApprox apa, boolean cc
) {
fwdFlow(arg, state, outercc, summaryCtx, argT, argAp, t, ap, apa) and
(if outercc instanceof CcCall then cc = true else cc = false) and
(if instanceofCcCall(outercc) then cc = true else cc = false) and
if ap instanceof ApNil then emptyAp = true else emptyAp = false
}
@@ -1652,6 +1715,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
DataFlowCall call, ArgNodeEx arg, CcCall ctx
) {
callEdgeArgParamRestricted(call, _, arg, _, _, _) and
instanceofCcCall(ctx) and
result = viableImplCallContextReducedInlineLate(call, ctx)
}
@@ -1667,6 +1731,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
bindingset[call, ctx]
pragma[inline_late]
private predicate viableImplNotCallContextReducedInlineLate(DataFlowCall call, Cc ctx) {
instanceofCc(ctx) and
viableImplNotCallContextReduced(call, ctx)
}
@@ -1676,6 +1741,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
DataFlowCall call, ArgNodeEx arg, Cc outercc
) {
callEdgeArgParamRestricted(call, _, arg, _, _, _) and
instanceofCc(outercc) and
viableImplNotCallContextReducedInlineLate(call, outercc)
}
@@ -1780,19 +1846,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
}
pragma[nomagic]
private DataFlowCallable viableImplCallContextReducedReverseRestricted(
DataFlowCall call, CcNoCall ctx
private DataFlowCall viableImplCallContextReducedReverseRestricted(
DataFlowCallable c, CcNoCall ctx
) {
result = viableImplCallContextReducedReverse(call, ctx) and
PrevStage::callEdgeReturn(call, result, _, _, _, _, _)
result = viableImplCallContextReducedReverse(c, ctx) and
PrevStage::callEdgeReturn(result, c, _, _, _, _, _)
}
bindingset[ctx, result]
bindingset[c, ctx]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedReverseInlineLate(
DataFlowCall call, CcNoCall ctx
private DataFlowCall viableImplCallContextReducedReverseInlineLate(
DataFlowCallable c, CcNoCall ctx
) {
result = viableImplCallContextReducedReverseRestricted(call, ctx)
result = viableImplCallContextReducedReverseRestricted(c, ctx)
}
bindingset[call]
@@ -1820,6 +1886,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
RetNodeEx ret, FlowState state, CcNoCall cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa
) {
instanceofCcNoCall(cc) and
fwdFlow(ret, state, cc, summaryCtx, argT, argAp, t, ap, apa)
}
@@ -1831,7 +1898,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
fwdFlowIntoRet(ret, _, innercc, _, _, _, _, _, apa) and
inner = ret.getEnclosingCallable() and
(
inner = viableImplCallContextReducedReverseInlineLate(call, innercc) and
call = viableImplCallContextReducedReverseInlineLate(inner, innercc) and
flowOutOfCallApaInlineLate(call, inner, ret, out, allowsFieldFlow, apa)
or
flowOutOfCallApaNotCallContextReduced(call, inner, ret, out, allowsFieldFlow, apa,
@@ -1879,6 +1946,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
pragma[nomagic]
private predicate fwdFlow1Param(ParamNodeEx p, FlowState state, CcCall cc, Typ t0, Ap ap) {
instanceofCcCall(cc) and
fwdFlow1(p, state, cc, _, _, _, t0, _, ap, _)
}
@@ -1945,6 +2013,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ApApprox argApa, Typ t, Ap ap, ApApprox apa
) {
exists(ReturnKindExt kind |
instanceofCcCall(ccc) and
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())), TypOption::some(argT),
pragma[only_bind_into](apSome(argAp)), t, ap, pragma[only_bind_into](apa)) and
@@ -2510,10 +2579,16 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
CcCall ccSomeCall() { result = true }
predicate instanceofCc(Cc cc) { any() }
predicate instanceofCcCall(CcCall cc) { any() }
predicate instanceofCcNoCall(CcNoCall cc) { any() }
class LocalCc = Unit;
bindingset[node, cc]
LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
bindingset[cc]
LocalCc getLocalCc(Cc cc) { any() }
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CcCall ctx) { none() }
@@ -2523,9 +2598,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
bindingset[call, c]
CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c) { any() }
DataFlowCallable viableImplCallContextReducedReverse(DataFlowCall call, CcNoCall ctx) {
none()
}
DataFlowCall viableImplCallContextReducedReverse(DataFlowCallable c, CcNoCall ctx) { none() }
predicate viableImplNotCallContextReducedReverse(CcNoCall ctx) { any() }
@@ -2533,105 +2606,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) { any() }
}
private signature module Level1CallContextInputSig {
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, CallContextSpecificCall ctx);
bindingset[call, ctx]
predicate noPrunedViableImplInCallContext(DataFlowCall call, CallContext ctx);
predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable);
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable);
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call);
DataFlowCall prunedViableImplInCallContextReverse(
DataFlowCallable callable, CallContextReturn ctx
);
}
private module Level1CallContext<Level1CallContextInputSig Input> {
class Cc = CallContext;
class CcCall = CallContextCall;
pragma[inline]
predicate matchesCall(CcCall cc, DataFlowCall call) { cc.matchesCall(call) }
class CcNoCall = CallContextNoCall;
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
module NoLocalCallContext {
class LocalCc = Unit;
bindingset[node, cc]
LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CcCall ctx) {
result = Input::prunedViableImplInCallContext(call, ctx)
}
bindingset[call, ctx]
predicate viableImplNotCallContextReduced(DataFlowCall call, Cc ctx) {
Input::noPrunedViableImplInCallContext(call, ctx)
}
bindingset[call, c]
CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c) {
if Input::recordDataFlowCallSiteDispatch(call, c)
then result = TSpecificCall(call)
else result = TSomeCall()
}
}
module LocalCallContext {
class LocalCc = LocalCallContext;
bindingset[node, cc]
LocalCc getLocalCc(NodeEx node, Cc cc) {
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
}
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CcCall ctx) {
result = Input::prunedViableImplInCallContext(call, ctx)
}
bindingset[call, ctx]
predicate viableImplNotCallContextReduced(DataFlowCall call, Cc ctx) {
Input::noPrunedViableImplInCallContext(call, ctx)
}
bindingset[call, c]
CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c) {
if
Input::recordDataFlowCallSiteDispatch(call, c) or
Input::recordDataFlowCallSiteUnreachable(call, c)
then result = TSpecificCall(call)
else result = TSomeCall()
}
}
DataFlowCallable viableImplCallContextReducedReverse(DataFlowCall call, CcNoCall ctx) {
call = Input::prunedViableImplInCallContextReverse(result, ctx)
}
predicate viableImplNotCallContextReducedReverse(CcNoCall ctx) {
ctx instanceof CallContextAny
}
bindingset[call, c]
CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
if Input::reducedViableImplInReturn(c, call)
then result = TReturn(c, call)
else result = ccNone()
}
}
private module Stage2Param implements MkStage<Stage1>::StageParam {
private module PrevStage = Stage1;
@@ -2669,11 +2643,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
private module Level1CallContextInput implements Level1CallContextInputSig {
import CachedCallContextSensitivity
}
import Level1CallContext<Level1CallContextInput>
import CachedCallContextSensitivity
import NoLocalCallContext
bindingset[node1, state1]
@@ -2831,7 +2801,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
Stage2::revFlow(node2, pragma[only_bind_into](state2), false)
or
additionalLocalStateStep(node1, state1, node2, state2) and
label = "" and
label = "Config" and
Stage2::revFlow(node1, state1, false) and
Stage2::revFlow(node2, state2, false)
}
@@ -2916,12 +2886,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;
@@ -2929,7 +2901,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) }
@@ -2947,30 +2919,27 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
additional module Level1CallContextInput implements Level1CallContextInputSig {
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = PrevStage::relevantCallEdgeIn/2;
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = PrevStage::relevantCallEdgeIn/2;
predicate relevantCallEdgeOut = PrevStage::relevantCallEdgeOut/2;
predicate relevantCallEdgeOut = PrevStage::relevantCallEdgeOut/2;
predicate reducedViableImplInCallContextCand =
CachedCallContextSensitivity::reducedViableImplInCallContext/3;
predicate reducedViableImplInCallContextCand =
CachedCallContextSensitivity::reducedViableImplInCallContext/3;
predicate reducedViableImplInReturnCand =
CachedCallContextSensitivity::reducedViableImplInReturn/2;
}
import CallContextSensitivity<CallContextSensitivityInput>
predicate reducedViableImplInReturnCand =
CachedCallContextSensitivity::reducedViableImplInReturn/2;
}
import Level1CallContext<Level1CallContextInput>
import CallContextSensitivity<CallContextSensitivityInput>
import NoLocalCallContext
predicate localStep(
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)
}
@@ -2993,7 +2962,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
@@ -3002,11 +2970,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>;
@@ -3016,7 +2980,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
}
@@ -3115,7 +3083,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)
}
}
@@ -3339,23 +3307,18 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
ApOption apSome(Ap ap) { result = TAccessPathApproxSome(ap) }
additional module Level1CallContextInput implements Level1CallContextInputSig {
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = PrevStage::relevantCallEdgeIn/2;
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = PrevStage::relevantCallEdgeIn/2;
predicate relevantCallEdgeOut = PrevStage::relevantCallEdgeOut/2;
predicate relevantCallEdgeOut = PrevStage::relevantCallEdgeOut/2;
predicate reducedViableImplInCallContextCand =
Stage3Param::Level1CallContextInput::reducedViableImplInCallContext/3;
predicate reducedViableImplInCallContextCand =
Stage3Param::reducedViableImplInCallContext/3;
predicate reducedViableImplInReturnCand =
Stage3Param::Level1CallContextInput::reducedViableImplInReturn/2;
}
import CallContextSensitivity<CallContextSensitivityInput>
predicate reducedViableImplInReturnCand = Stage3Param::reducedViableImplInReturn/2;
}
import Level1CallContext<Level1CallContextInput>
import CallContextSensitivity<CallContextSensitivityInput>
import LocalCallContext
predicate localStep(
@@ -3376,7 +3339,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType) {
compatibleTypes(typ, contentType)
compatibleTypesFilter(typ, contentType)
}
}
@@ -3389,7 +3352,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
exists(AccessPathApprox apa0 |
Stage5::parameterMayFlowThrough(p, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
Stage5::fwdFlow(n, state, any(Stage5Param::CcCall ccc), TParamNodeSome(p.asNode()), _,
TAccessPathApproxSome(apa), _, apa0, _)
)
}
@@ -3443,6 +3406,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
Location getLocation() { result = p.getLocation() }
}
pragma[nomagic]
private predicate stage5ConsCand(Content c, DataFlowType t, AccessPathFront apf, int len) {
Stage5::consCand(c, t, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1))
}
/**
* Gets the number of length 2 access path approximations that correspond to `apa`.
*/
@@ -3450,11 +3418,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
exists(Content c, int len |
c = apa.getHead() and
len = apa.len() and
result =
strictcount(DataFlowType t, AccessPathFront apf |
Stage5::consCand(c, t,
any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1))
)
result = strictcount(DataFlowType t, AccessPathFront apf | stage5ConsCand(c, t, apf, len))
)
}
@@ -3567,6 +3531,36 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
}
private module PrunedCallContextSensitivityStage5 {
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = Stage5::relevantCallEdgeIn/2;
predicate relevantCallEdgeOut = Stage5::relevantCallEdgeOut/2;
predicate reducedViableImplInCallContextCand =
Stage5Param::reducedViableImplInCallContext/3;
predicate reducedViableImplInReturnCand = Stage5Param::reducedViableImplInReturn/2;
}
import CallContextSensitivity<CallContextSensitivityInput>
import LocalCallContext
}
private class CallContext = PrunedCallContextSensitivityStage5::Cc;
private class CallContextCall = PrunedCallContextSensitivityStage5::CcCall;
private class CallContextNoCall = PrunedCallContextSensitivityStage5::CcNoCall;
private predicate callContextNone = PrunedCallContextSensitivityStage5::ccNone/0;
private predicate callContextSomeCall = PrunedCallContextSensitivityStage5::ccSomeCall/0;
private predicate sourceCallCtx(CallContext cc) {
if hasSourceCallCtx() then cc = callContextSomeCall() else cc = callContextNone()
}
private newtype TPathNode =
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap,
@@ -3802,6 +3796,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
not this instanceof PathNodeSink
or
this.getNodeEx() instanceof TNodeImplicitRead
or
hiddenNode(this.getNodeEx().asParamReturnNode())
)
}
@@ -3925,6 +3921,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the parameter node through which data is returned, if any. */
final ParameterNode asParameterReturnNode() { result = super.getNodeEx().asParamReturnNode() }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
@@ -3941,10 +3940,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group) }
}
private import codeql.dataflow.test.ProvenancePathGraph as ProvenancePathGraph
/**
* Provides the query predicates needed to include a graph in a path-problem query.
*/
module PathGraph implements PathGraphSig<PathNode> {
module PathGraph implements PathGraphSig<PathNode>, ProvenancePathGraph::PathGraphSig<PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b, string key, string val) {
a.(PathNodeImpl).getANonHiddenSuccessor(val) = b and
@@ -4143,9 +4144,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
state = mid.getState() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
midnode.getEnclosingCallable()) and
localCC = PrunedCallContextSensitivityStage5::getLocalCc(cc) and
t = mid.getType() and
ap = mid.getAp() and
summaryLabel = mid.getSummaryLabel()
@@ -4191,7 +4190,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
jumpStepEx(mid.getNodeExOutgoing(), node) and
state = mid.getState() and
cc instanceof CallContextAny and
cc = callContextNone() and
sc instanceof SummaryCtxNone and
t = mid.getType() and
ap = mid.getAp() and
@@ -4201,7 +4200,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
additionalJumpStep(mid.getNodeExOutgoing(), node, label) and
state = mid.getState() and
cc instanceof CallContextAny and
cc = callContextNone() and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
t = node.getDataFlowType() and
@@ -4210,14 +4209,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
summaryLabel = "-"
or
additionalJumpStateStep(mid.getNodeExOutgoing(), mid.getState(), node, state) and
cc instanceof CallContextAny and
cc = callContextNone() and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
t = node.getDataFlowType() and
ap = TAccessPathNil() and
isStoreStep = false and
summaryLabel = "-" and
label = ""
label = "Config"
or
exists(Content c, DataFlowType t0, AccessPath ap0 |
pathStoreStep(mid, node, state, t0, ap0, c, t, cc) and
@@ -4280,7 +4279,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)
)
}
@@ -4300,22 +4299,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
}
private module PrunedCallContextSensitivityStage5 {
private module CallContextSensitivityInput implements CallContextSensitivityInputSig {
predicate relevantCallEdgeIn = Stage5::relevantCallEdgeIn/2;
predicate relevantCallEdgeOut = Stage5::relevantCallEdgeOut/2;
predicate reducedViableImplInCallContextCand =
Stage5Param::Level1CallContextInput::reducedViableImplInCallContext/3;
predicate reducedViableImplInReturnCand =
Stage5Param::Level1CallContextInput::reducedViableImplInReturn/2;
}
import CallContextSensitivity<CallContextSensitivityInput>
}
pragma[nomagic]
private predicate pathOutOfCallable1(
PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, FlowState state, CallContext cc,
@@ -4325,11 +4308,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
pathOutOfCallable0(mid, pos, state, innercc, apa) and
c = pos.getCallable() and
kind = pos.getKind() and
PrunedCallContextSensitivityStage5::resolveReturn(innercc, c, call)
|
if PrunedCallContextSensitivityStage5::reducedViableImplInReturn(c, call)
then cc = TReturn(c, call)
else cc = TAnyCallContext()
PrunedCallContextSensitivityStage5::resolveReturn(innercc, c, call) and
cc = PrunedCallContextSensitivityStage5::getCallContextReturn(c, call)
)
}
@@ -4415,11 +4395,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if PrunedCallContextSensitivityStage5::recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
) and
innercc = PrunedCallContextSensitivityStage5::getCallContextCall(call, callable)
)
}
@@ -4767,22 +4744,32 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
private predicate flagDisable() { none() }
module FlowExplorationFwd<explorationLimitSig/0 explorationLimit> {
private import FlowExploration<explorationLimit/0, flagEnable/0, flagDisable/0>
import Public
private import FlowExploration<explorationLimit/0, flagEnable/0, flagDisable/0> as F
import F::Public
predicate partialFlow = partialFlowFwd/3;
predicate partialFlow = F::partialFlowFwd/3;
}
module FlowExplorationRev<explorationLimitSig/0 explorationLimit> {
private import FlowExploration<explorationLimit/0, flagDisable/0, flagEnable/0>
import Public
private import FlowExploration<explorationLimit/0, flagDisable/0, flagEnable/0> as F
import F::Public
predicate partialFlow = partialFlowRev/3;
predicate partialFlow = F::partialFlowRev/3;
}
private module FlowExploration<
explorationLimitSig/0 explorationLimit, flag/0 flagFwd, flag/0 flagRev>
{
class CallContext = CachedCallContextSensitivity::Cc;
class CallContextCall = CachedCallContextSensitivity::CcCall;
class CallContextNoCall = CachedCallContextSensitivity::CcNoCall;
predicate callContextNone = CachedCallContextSensitivity::ccNone/0;
predicate callContextSomeCall = CachedCallContextSensitivity::ccSomeCall/0;
private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2) {
exists(NodeEx node1, NodeEx node2 |
jumpStepEx(node1, node2)
@@ -4953,7 +4940,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
) {
flagFwd() and
sourceNode(node, state) and
cc instanceof CallContextAny and
cc = callContextNone() and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
sc3 = TSummaryCtx3None() and
@@ -5167,7 +5154,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
predicate isSource() {
sourceNode(node, state) and
cc instanceof CallContextAny and
cc = callContextNone() and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
sc3 = TSummaryCtx3None() and
@@ -5219,7 +5206,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap,
boolean isStoreStep
) {
not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
not isUnreachableInCall1(node,
CachedCallContextSensitivity::LocalCallContext::getLocalCc(cc)) and
(
localFlowStepEx(mid.getNodeEx(), node, _) and
state = mid.getState() and
@@ -5256,7 +5244,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
jumpStepEx(mid.getNodeEx(), node) and
state = mid.getState() and
cc instanceof CallContextAny and
cc = callContextNone() and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
sc3 = TSummaryCtx3None() and
@@ -5267,7 +5255,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
additionalJumpStep(mid.getNodeEx(), node, _) and
state = mid.getState() and
cc instanceof CallContextAny and
cc = callContextNone() and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
sc3 = TSummaryCtx3None() and
@@ -5278,7 +5266,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
isStoreStep = false
or
additionalJumpStateStep(mid.getNodeEx(), mid.getState(), node, state) and
cc instanceof CallContextAny and
cc = callContextNone() and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
sc3 = TSummaryCtx3None() and
@@ -5341,7 +5329,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)
)
}
@@ -5393,11 +5381,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
partialPathOutOfCallable0(mid, pos, state, innercc, t, ap) and
c = pos.getCallable() and
kind = pos.getKind() and
CachedCallContextSensitivity::resolveReturn(innercc, c, call)
|
if CachedCallContextSensitivity::reducedViableImplInReturn(c, call)
then cc = TReturn(c, call)
else cc = TAnyCallContext()
CachedCallContextSensitivity::resolveReturn(innercc, c, call) and
cc = CachedCallContextSensitivity::getCallContextReturn(c, call)
)
}
@@ -5448,11 +5433,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
sc1 = TSummaryCtx1Param(p) and
sc2 = TSummaryCtx2Some(state) and
sc3 = TSummaryCtx3Some(t) and
sc4 = TSummaryCtx4Some(ap)
|
if CachedCallContextSensitivity::recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call)
else innercc = TSomeCall()
sc4 = TSummaryCtx4Some(ap) and
innercc =
CachedCallContextSensitivity::LocalCallContext::getCallContextCall(call, callable)
)
}
@@ -5620,7 +5603,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap) and
pos = getReturnPosition(node.asNode()) and
pos = node.(RetNodeEx).getReturnPosition() and
isStoreStep = false
)
or

View File

@@ -1,7 +1,10 @@
private import codeql.dataflow.DataFlow
private import codeql.typetracking.TypeTracking as Tt
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
@@ -137,7 +140,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
predicate callStep(Node n1, LocalSourceNode n2) { viableParamArg(_, n2, n1) }
predicate returnStep(Node n1, LocalSourceNode n2) {
viableReturnPosOut(_, getReturnPosition(n1), n2)
viableReturnPosOut(_, [getValueReturnPosition(n1), getParamReturnPosition(n1, _)], n2)
}
predicate hasFeatureBacktrackStoreTarget() { none() }
@@ -222,9 +225,18 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
)
}
pragma[noinline]
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
pragma[nomagic]
private predicate hasSimpleReturnKindIn(ReturnNode ret, ReturnKind kind, DataFlowCallable c) {
c = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
}
pragma[nomagic]
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret) {
exists(ReturnKind kind, DataFlowCallable c |
hasSimpleReturnKindIn(ret, kind, c) and
result = TReturnPositionSimple0(c, kind)
)
}
pragma[nomagic]
@@ -276,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()
}
@@ -349,7 +361,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
// flow out of a callable
exists(TReturnPositionSimple pos |
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
pos = getReturnPositionSimple(node) and
toReturn = true
)
}
@@ -430,7 +442,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
private import Input
pragma[nomagic]
DataFlowCallable viableImplInCallContextExtIn(DataFlowCall call, DataFlowCall ctx) {
private DataFlowCallable viableImplInCallContextExtIn(DataFlowCall call, DataFlowCall ctx) {
reducedViableImplInCallContextCand(call, _, ctx) and
result = viableImplInCallContextExt(call, ctx) and
relevantCallEdgeIn(call, result)
@@ -455,15 +467,15 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
*/
pragma[nomagic]
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) {
exists(Node n |
exists(NodeRegion nr |
relevantCallEdgeIn(call, callable) and
getNodeEnclosingCallable(n) = callable and
isUnreachableInCallCached(n, call)
getNodeRegionEnclosingCallable(nr) = callable and
isUnreachableInCallCached(nr, call)
)
}
pragma[nomagic]
DataFlowCallable viableImplInCallContextExtOut(DataFlowCall call, DataFlowCall ctx) {
private DataFlowCallable viableImplInCallContextExtOut(DataFlowCall call, DataFlowCall ctx) {
exists(DataFlowCallable c |
reducedViableImplInReturnCand(result, call) and
result = viableImplInCallContextExt(call, ctx) and
@@ -490,14 +502,170 @@ 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 module CallSets = MakeSets<CallSetsInput>;
private module CallSetOption = Option<CallSets::ValueSet>;
/**
* A set of call sites for which dispatch is affected by the call context.
*
* A `None` value indicates the empty set.
*/
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 module DispatchSets = MakeSets<DispatchSetsInput>;
private module DispatchSetsOption = Option<DispatchSets::ValueSet>;
/**
* A set of call edges that are allowed in the call context. This applies to
* all calls in the associated `CallSet`, in particular, this means that if
* a call has no associated edges in the `DispatchSet`, then either all
* edges are allowed or none are depending on whether the call is in the
* `CallSet`.
*
* A `None` value indicates the empty set.
*/
private class DispatchSet = DispatchSetsOption::Option;
private predicate relevantCtx(TCallEdge ctx) {
exists(CallSets::getValueSet(ctx)) or exists(getUnreachableSet(ctx))
}
pragma[nomagic]
private predicate hasCtx(
TCallEdge ctx, CallSet calls, DispatchSet tgts, UnreachableSetOption unreachable
) {
relevantCtx(ctx) and
(
CallSets::getValueSet(ctx) = calls.asSome()
or
not exists(CallSets::getValueSet(ctx)) and calls.isNone()
) and
(
DispatchSets::getValueSet(ctx) = tgts.asSome()
or
not exists(DispatchSets::getValueSet(ctx)) and tgts.isNone()
) and
(
getUnreachableSet(ctx) = unreachable.asSome()
or
not exists(getUnreachableSet(ctx)) and unreachable.isNone()
)
}
private newtype TCallContext =
TAnyCallContext() or
TSpecificCall(CallSet calls, DispatchSet tgts, UnreachableSetOption unreachable) {
hasCtx(_, calls, tgts, unreachable)
} or
TSomeCall() or
TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) }
/**
* A call context to restrict the targets of virtual dispatch and prune local flow.
*
* There are four cases:
* - `TAnyCallContext()` : No restrictions on method flow.
* - `TSpecificCall(CallSet calls, DispatchSet tgts, UnreachableSetOption unreachable)` :
* Flow entered through a specific call that improves the set of viable
* dispatch targets for all of `calls` to the set of dispatch targets in
* `tgts`, and/or the specific call prunes unreachable nodes in the
* current callable as given by `unreachable`.
* - `TSomeCall()` : Flow entered through a parameter. The
* originating call does not improve the set of dispatch targets for any
* method call in the current callable and was therefore not recorded.
* - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and
* this dispatch target of `call` implies a reduced set of dispatch origins
* to which data may flow if it should reach a `return` statement.
*/
abstract private class CallContext extends TCallContext {
abstract string toString();
}
abstract private class CallContextCall extends CallContext { }
abstract private class CallContextNoCall extends CallContext { }
private class CallContextAny extends CallContextNoCall, TAnyCallContext {
override string toString() { result = "CcAny" }
}
private class CallContextSpecificCall extends CallContextCall, TSpecificCall {
override string toString() { result = "CcCallSpecific" }
}
private class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
}
private class CallContextReturn extends CallContextNoCall, TReturn {
override string toString() {
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
}
}
pragma[nomagic]
CallContextCall getSpecificCallContextCall(DataFlowCall call, DataFlowCallable c) {
exists(CallSet calls, DispatchSet tgts, UnreachableSetOption unreachable |
hasCtx(TMkCallEdge(call, c), calls, tgts, unreachable) and
result = TSpecificCall(calls, tgts, unreachable)
)
}
pragma[nomagic]
predicate callContextAffectsDispatch(DataFlowCall call, CallContext ctx) {
exists(CallSet calls | ctx = TSpecificCall(calls, _, _) | calls.asSome().contains(call))
}
CallContextNoCall getSpecificCallContextReturn(DataFlowCallable c, DataFlowCall call) {
result = TReturn(c, call)
}
signature module PrunedViableImplInputSig {
predicate reducedViableImplInCallContext(
DataFlowCall call, DataFlowCallable c, DataFlowCall ctx
);
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call);
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable c);
CallContextCall getSpecificCallContextCall(DataFlowCall call, DataFlowCallable c);
predicate callContextAffectsDispatch(DataFlowCall call, CallContext ctx);
CallContextNoCall getSpecificCallContextReturn(DataFlowCallable c, DataFlowCall call);
}
/**
@@ -505,31 +673,44 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
* of the input predicates in `CachedCallContextSensitivity`.
*/
module PrunedViableImpl<PrunedViableImplInputSig Input2> {
class Cc = CallContext;
class CcCall = CallContextCall;
pragma[inline]
predicate matchesCall(CcCall cc, DataFlowCall call) {
cc = Input2::getSpecificCallContextCall(call, _) or
cc = ccSomeCall()
}
class CcNoCall = CallContextNoCall;
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
predicate instanceofCc(Cc cc) { any() }
predicate instanceofCcCall(CcCall cc) { any() }
predicate instanceofCcNoCall(CcNoCall cc) { any() }
/**
* Gets a viable run-time dispatch target for the call `call` in the
* context `ctx`. This is restricted to those calls for which a context
* makes a difference.
*/
pragma[nomagic]
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, CallContextSpecificCall ctx) {
exists(DataFlowCall outer | ctx = TSpecificCall(outer) |
result = viableImplInCallContextExtIn(call, outer) and
Input2::reducedViableImplInCallContext(call, _, outer)
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CallContextCall ctx) {
exists(DispatchSet tgts | ctx = TSpecificCall(_, tgts, _) |
tgts.asSome().contains(TMkCallEdge(call, result))
)
}
/** Holds if `call` does not have a reduced set of dispatch targets in call context `ctx`. */
bindingset[call, ctx]
predicate noPrunedViableImplInCallContext(DataFlowCall call, CallContext ctx) {
exists(DataFlowCall outer | ctx = TSpecificCall(outer) |
not Input2::reducedViableImplInCallContext(call, _, outer)
)
or
ctx instanceof CallContextSomeCall
or
ctx instanceof CallContextAny
or
ctx instanceof CallContextReturn
predicate viableImplNotCallContextReduced(DataFlowCall call, CallContext ctx) {
not Input2::callContextAffectsDispatch(call, ctx)
}
/**
@@ -538,9 +719,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
*/
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = prunedViableImplInCallContext(call, cc)
result = viableImplCallContextReduced(call, cc)
or
noPrunedViableImplInCallContext(call, cc) and
viableImplNotCallContextReduced(call, cc) and
relevantCallEdgeIn(call, result)
}
@@ -550,17 +731,25 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
* the possible call sites are restricted.
*/
pragma[nomagic]
DataFlowCall prunedViableImplInCallContextReverse(
DataFlowCallable callable, CallContextReturn ctx
DataFlowCall viableImplCallContextReducedReverse(
DataFlowCallable callable, CallContextNoCall ctx
) {
exists(DataFlowCallable c0, DataFlowCall call0 |
callEnclosingCallable(call0, callable) and
ctx = TReturn(c0, call0) and
c0 = viableImplInCallContextExtOut(call0, result) and
Input2::reducedViableImplInReturn(c0, call0)
reducedViableImplInReturn(c0, call0)
)
}
/**
* Holds if a return does not have a reduced set of viable call sites to
* return to in call context `ctx`.
*/
predicate viableImplNotCallContextReducedReverse(CallContextNoCall ctx) {
ctx instanceof CallContextAny
}
/**
* Resolves a return from `callable` in `cc` to `call`.
*/
@@ -568,14 +757,22 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
predicate resolveReturn(CallContextNoCall cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and relevantCallEdgeOut(call, callable)
or
call = prunedViableImplInCallContextReverse(callable, cc)
call = viableImplCallContextReducedReverse(callable, cc)
}
/** Gets the call context when returning from `c` to `call`. */
bindingset[call, c]
CallContextNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call) {
result = Input2::getSpecificCallContextReturn(c, call)
or
not exists(Input2::getSpecificCallContextReturn(c, call)) and result = TAnyCallContext()
}
/**
* Holds if the call context `call` improves virtual dispatch in `callable`.
*/
pragma[nomagic]
predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) {
private predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) {
Input2::reducedViableImplInCallContext(_, callable, call)
}
@@ -587,25 +784,79 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
Input2::recordDataFlowCallSiteUnreachable(call, c) or
recordDataFlowCallSiteDispatch(call, c)
}
module NoLocalCallContext {
class LocalCc = Unit;
bindingset[cc]
LocalCc getLocalCc(CallContext cc) { any() }
bindingset[call, c]
CallContextCall getCallContextCall(DataFlowCall call, DataFlowCallable c) {
if recordDataFlowCallSiteDispatch(call, c)
then result = Input2::getSpecificCallContextCall(call, c)
else result = TSomeCall()
}
}
module LocalCallContext {
class LocalCc = LocalCallContext;
private UnreachableSet getUnreachable(CallContext ctx) {
exists(UnreachableSetOption unreachable | ctx = TSpecificCall(_, _, unreachable) |
result = unreachable.asSome()
)
}
private LocalCallContext getLocalCallContext(CallContext ctx) {
result = TSpecificLocalCall(getUnreachable(ctx))
or
not exists(getUnreachable(ctx)) and
result instanceof LocalCallContextAny
}
bindingset[cc]
pragma[inline_late]
LocalCc getLocalCc(CallContext cc) { result = getLocalCallContext(cc) }
bindingset[call, c]
CallContextCall getCallContextCall(DataFlowCall call, DataFlowCallable c) {
if recordDataFlowCallSite(call, c)
then result = Input2::getSpecificCallContextCall(call, c)
else result = TSomeCall()
}
}
}
private predicate reducedViableImplInCallContextAlias = reducedViableImplInCallContext/3;
private predicate reducedViableImplInReturnAlias = reducedViableImplInReturn/2;
private predicate recordDataFlowCallSiteUnreachableAlias = recordDataFlowCallSiteUnreachable/2;
private predicate getSpecificCallContextCallAlias = getSpecificCallContextCall/2;
private predicate callContextAffectsDispatchAlias = callContextAffectsDispatch/2;
private predicate getSpecificCallContextReturnAlias = getSpecificCallContextReturn/2;
private module DefaultPrunedViableImplInput implements PrunedViableImplInputSig {
predicate reducedViableImplInCallContext = reducedViableImplInCallContextAlias/3;
predicate reducedViableImplInReturn = reducedViableImplInReturnAlias/2;
predicate recordDataFlowCallSiteUnreachable = recordDataFlowCallSiteUnreachableAlias/2;
predicate getSpecificCallContextCall = getSpecificCallContextCallAlias/2;
predicate callContextAffectsDispatch = callContextAffectsDispatchAlias/2;
predicate getSpecificCallContextReturn = getSpecificCallContextReturnAlias/2;
}
import PrunedViableImpl<DefaultPrunedViableImplInput>
}
module SndLevelScopeOption = Option<DataFlowSecondLevelScope>;
class SndLevelScopeOption = SndLevelScopeOption::Option;
cached
private module Cached {
/**
@@ -617,7 +868,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
predicate forceCachingInSameStage() { any() }
cached
DataFlowSecondLevelScope getSecondLevelScopeCached(Node n) { result = getSecondLevelScope(n) }
SndLevelScopeOption getSecondLevelScopeCached(Node n) {
result = SndLevelScopeOption::some(getSecondLevelScope(n))
or
result instanceof SndLevelScopeOption::None and
not exists(getSecondLevelScope(n))
}
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) }
@@ -630,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) }
@@ -640,7 +910,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
predicate isUnreachableInCallCached(NodeRegion nr, DataFlowCall call) {
isUnreachableInCall(nr, call)
}
cached
predicate outNodeExt(Node n) {
@@ -663,13 +935,17 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, ParameterPosition pos |
predicate valueReturnNode(ReturnNode n, ReturnKindExt k) { k = TValueReturn(n.getKind()) }
cached
predicate paramReturnNode(
PostUpdateNode n, ParamNode p, SndLevelScopeOption scope, ReturnKindExt k
) {
exists(ParameterPosition pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
k = TParamUpdate(pos) and
scope = getSecondLevelScopeCached(n)
)
}
@@ -782,15 +1058,36 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
Impl1::reducedViableImplInReturn(c, call)
}
cached
CcCall getSpecificCallContextCall(DataFlowCall call, DataFlowCallable c) {
result = Impl1::getSpecificCallContextCall(call, c)
}
cached
predicate callContextAffectsDispatch(DataFlowCall call, Cc ctx) {
Impl1::callContextAffectsDispatch(call, ctx)
}
cached
CcNoCall getSpecificCallContextReturn(DataFlowCallable c, DataFlowCall call) {
result = Impl1::getSpecificCallContextReturn(c, call)
}
private module PrunedViableImplInput implements Impl1::PrunedViableImplInputSig {
predicate reducedViableImplInCallContext =
CachedCallContextSensitivity::reducedViableImplInCallContext/3;
predicate reducedViableImplInReturn =
CachedCallContextSensitivity::reducedViableImplInReturn/2;
predicate recordDataFlowCallSiteUnreachable =
CachedCallContextSensitivity::recordDataFlowCallSiteUnreachable/2;
predicate getSpecificCallContextCall =
CachedCallContextSensitivity::getSpecificCallContextCall/2;
predicate callContextAffectsDispatch =
CachedCallContextSensitivity::callContextAffectsDispatch/2;
predicate getSpecificCallContextReturn =
CachedCallContextSensitivity::getSpecificCallContextReturn/2;
}
private module Impl2 = Impl1::PrunedViableImpl<PrunedViableImplInput>;
@@ -798,15 +1095,22 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
import Impl2
cached
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, CallContextSpecificCall ctx) {
result = Impl2::prunedViableImplInCallContext(call, ctx)
predicate instanceofCc(Cc cc) { any() }
cached
predicate instanceofCcCall(CcCall cc) { any() }
cached
predicate instanceofCcNoCall(CcNoCall cc) { any() }
cached
DataFlowCallable viableImplCallContextReduced(DataFlowCall call, CcCall ctx) {
result = Impl2::viableImplCallContextReduced(call, ctx)
}
cached
DataFlowCall prunedViableImplInCallContextReverse(
DataFlowCallable callable, CallContextReturn ctx
) {
result = Impl2::prunedViableImplInCallContextReverse(callable, ctx)
DataFlowCall viableImplCallContextReducedReverse(DataFlowCallable callable, CcNoCall ctx) {
result = Impl2::viableImplCallContextReducedReverse(callable, ctx)
}
}
@@ -828,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)
)
}
@@ -981,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()
}
@@ -1017,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)
@@ -1078,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))
)
}
@@ -1208,29 +1512,74 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
ContentApprox getContentApproxCached(Content c) { result = getContentApprox(c) }
cached
newtype TCallContext =
TAnyCallContext() or
TSpecificCall(DataFlowCall call) {
CachedCallContextSensitivity::recordDataFlowCallSite(call, _)
} or
TSomeCall() or
TReturn(DataFlowCallable c, DataFlowCall call) {
CachedCallContextSensitivity::reducedViableImplInReturn(c, call)
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()
)
}
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>;
/** A set of nodes that is unreachable in some call context. */
cached
class UnreachableSet instanceof UnreachableSets::ValueSet {
cached
string toString() { result = "Unreachable" }
cached
predicate contains(Node n) { exists(NodeRegion nr | super.contains(nr) and nr.contains(n)) }
cached
DataFlowCallable getEnclosingCallable() {
exists(NodeRegion nr | super.contains(nr) and result = getNodeRegionEnclosingCallable(nr))
}
}
cached
UnreachableSet getUnreachableSet(TCallEdge edge) { result = UnreachableSets::getValueSet(edge) }
private module UnreachableSetOption = Option<UnreachableSet>;
class UnreachableSetOption = UnreachableSetOption::Option;
cached
newtype TReturnPosition =
TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) {
exists(ReturnNodeExt ret |
c = returnNodeGetEnclosingCallable(ret) and
kind = ret.getKind()
)
hasValueReturnKindIn(_, kind, c)
or
hasParamReturnKindIn(_, _, kind, c)
}
cached
newtype TLocalFlowCallContext =
TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
TSpecificLocalCall(UnreachableSets::ValueSet ns)
cached
newtype TReturnKindExt =
@@ -1279,9 +1628,23 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
}
bindingset[call, tgt]
pragma[inline_late]
private TCallEdge mkCallEdge(DataFlowCall call, DataFlowCallable tgt) {
result = TMkCallEdge(call, tgt)
}
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
@@ -1362,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 |
@@ -1373,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 |
@@ -1413,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 |
@@ -1482,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
)
}
/**
@@ -1604,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)
)
}
@@ -1648,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)
)
}
@@ -1703,76 +2071,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
string toString() { if this.isSome() then result = "Some(..)" else result = "None()" }
}
/**
* A call context to restrict the targets of virtual dispatch, prune local flow,
* and match the call sites of flow into a method with flow out of a method.
*
* There are four cases:
* - `TAnyCallContext()` : No restrictions on method flow.
* - `TSpecificCall(DataFlowCall call)` : Flow entered through the
* given `call`. This call improves the set of viable
* dispatch targets for at least one method call in the current callable
* or helps prune unreachable nodes in the current callable.
* - `TSomeCall()` : Flow entered through a parameter. The
* originating call does not improve the set of dispatch targets for any
* method call in the current callable and was therefore not recorded.
* - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and
* this dispatch target of `call` implies a reduced set of dispatch origins
* to which data may flow if it should reach a `return` statement.
*/
abstract class CallContext extends TCallContext {
abstract string toString();
/** Holds if this call context is relevant for `callable`. */
abstract predicate relevantFor(DataFlowCallable callable);
}
abstract class CallContextNoCall extends CallContext { }
class CallContextAny extends CallContextNoCall, TAnyCallContext {
override string toString() { result = "CcAny" }
override predicate relevantFor(DataFlowCallable callable) { any() }
}
abstract class CallContextCall extends CallContext {
/** Holds if this call context may be `call`. */
bindingset[call]
abstract predicate matchesCall(DataFlowCall call);
}
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
override string toString() {
exists(DataFlowCall call | this = TSpecificCall(call) | result = "CcCall(" + call + ")")
}
override predicate relevantFor(DataFlowCallable callable) {
CachedCallContextSensitivity::recordDataFlowCallSite(this.getCall(), callable)
}
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
DataFlowCall getCall() { this = TSpecificCall(result) }
}
class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { any() }
override predicate matchesCall(DataFlowCall call) { any() }
}
class CallContextReturn extends CallContextNoCall, TReturn {
override string toString() {
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
}
override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
}
}
/**
* A call context that is relevant for pruning local flow.
*/
@@ -1790,30 +2088,22 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
}
class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall {
LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) }
LocalCallContextSpecificCall() { this = TSpecificLocalCall(ns) }
DataFlowCall call;
UnreachableSet ns;
DataFlowCall getCall() { result = call }
override string toString() { result = "LocalCcCall" }
override string toString() { result = "LocalCcCall(" + call + ")" }
override predicate relevantFor(DataFlowCallable callable) {
ns.getEnclosingCallable() = callable
}
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
/** Holds if this call context makes `n` unreachable. */
predicate unreachable(Node n) { ns.contains(n) }
}
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
}
/**
* Gets the local call context given the call context and the callable that
* the contexts apply to.
*/
LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) {
ctx.relevantFor(callable) and
if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable)
then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall()
else result instanceof LocalCallContextAny
private DataFlowCallable getNodeRegionEnclosingCallable(NodeRegion nr) {
exists(Node n | nr.contains(n) | getNodeEnclosingCallable(n) = result)
}
/**
@@ -1842,17 +2132,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
}
}
/**
* A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/
class ReturnNodeExt extends NodeFinal {
ReturnNodeExt() { returnNodeExt(this, _) }
/** Gets the kind of this returned value. */
ReturnKindExt getKind() { returnNodeExt(this, result) }
}
/**
* A node to which data can flow from a call. Either an ordinary out node
* or a post-update node associated with a call argument.
@@ -1930,20 +2209,34 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
}
pragma[noinline]
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
result = getNodeEnclosingCallable(ret)
pragma[nomagic]
private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) {
c = getNodeEnclosingCallable(ret) and
valueReturnNode(ret, kind)
}
pragma[noinline]
private ReturnPosition getReturnPosition0(ReturnNodeExt ret, ReturnKindExt kind) {
result.getCallable() = returnNodeGetEnclosingCallable(ret) and
kind = result.getKind()
pragma[nomagic]
private predicate hasParamReturnKindIn(
PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c
) {
c = getNodeEnclosingCallable(n) and
paramReturnNode(n, p, _, kind)
}
pragma[noinline]
ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
pragma[nomagic]
ReturnPosition getValueReturnPosition(ReturnNode ret) {
exists(ReturnKindExt kind, DataFlowCallable c |
hasValueReturnKindIn(ret, kind, c) and
result = TReturnPosition0(c, kind)
)
}
pragma[nomagic]
ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) {
exists(ReturnKindExt kind, DataFlowCallable c |
hasParamReturnKindIn(n, p, kind, c) and
result = TReturnPosition0(c, kind)
)
}
/** An optional Boolean value. */

View File

@@ -187,8 +187,9 @@ module MakeConsistency<
}
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
isUnreachableInCall(n, call) and
exists(DataFlowCallable c |
exists(DataFlowCallable c, NodeRegion nr |
isUnreachableInCall(nr, call) and
nr.contains(n) and
c = nodeGetEnclosingCallable(n) and
not viableCallable(call) = c
) and

View File

@@ -4,7 +4,6 @@
private import codeql.dataflow.DataFlow as DF
private import codeql.util.Location
private import DataFlowImpl
private import AccessPathSyntax as AccessPathSyntax
/**
@@ -253,6 +252,13 @@ module Make<
* that has provenance `provenance`.
*/
predicate hasProvenance(Provenance provenance) { provenance = "manual" }
/**
* Holds if there exists a model for which this callable is an exact
* match, that is, no overriding was used to identify this callable from
* the model.
*/
predicate hasExactModel() { none() }
}
final private class NeutralCallableFinal = NeutralCallable;
@@ -264,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.
*/
@@ -292,6 +312,13 @@ module Make<
* Gets the kind of the neutral.
*/
abstract string getKind();
/**
* Holds if there exists a model for which this callable is an exact
* match, that is, no overriding was used to identify this callable from
* the model.
*/
predicate hasExactModel() { none() }
}
}
@@ -1286,10 +1313,8 @@ module Make<
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
exists(ReturnKind rk, SummaryNode ret, DataFlowCall call |
summaryLocalStep(summaryArgParam(call, arg, sc), ret, true, _) and
summaryReturnNode(ret, pragma[only_bind_into](rk)) and
out = getAnOutNode(call, pragma[only_bind_into](rk))
exists(SummaryNode ret |
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _)
)
}
@@ -1694,10 +1719,11 @@ module Make<
)
)
or
exists(ReturnNodeExt ret |
exists(ReturnNode ret, ValueReturnKind kind |
c = "ReturnValue" and
ret = node.asNode() and
ret.getKind().(ValueReturnKind).getKind() = getStandardReturnValueKind() and
valueReturnNode(ret, kind) and
kind.getKind() = getStandardReturnValueKind() and
mid.asCallable() = getNodeEnclosingCallable(ret)
)
or
@@ -1727,6 +1753,37 @@ module Make<
)
}
final private class SourceOrSinkElementFinal = SourceOrSinkElement;
bindingset[this]
abstract private class SourceSinkModelCallableBase extends SourceOrSinkElementFinal {
/**
* Holds if there exists a manual model that applies to this.
*/
final predicate hasManualModel() { any(Provenance p | this.hasProvenance(p)).isManual() }
/**
* Holds if this has provenance `p`.
*/
abstract predicate hasProvenance(Provenance p);
}
/**
* A callable that has a source model.
*/
abstract class SourceModelCallable extends SourceSinkModelCallableBase {
bindingset[this]
SourceModelCallable() { exists(this) }
}
/**
* A callable that has a sink model.
*/
abstract class SinkModelCallable extends SourceSinkModelCallableBase {
bindingset[this]
SinkModelCallable() { exists(this) }
}
/** A source or sink relevant for testing. */
signature class RelevantSourceOrSinkElementSig extends SourceOrSinkElement {
/** Gets the string representation of this callable used by `source/1` or `sink/1`. */

View File

@@ -0,0 +1,85 @@
/**
* Provides a module for renumbering MaD IDs in data flow path explanations in
* order to produce more stable test output.
*
* 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 {
string toString();
}
signature module PathGraphSig<PathNodeSig PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
predicate edges(PathNode a, PathNode b, string key, string val);
/** Holds if `n` is a node in the graph of data flow path explanations. */
predicate nodes(PathNode n, string key, string val);
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
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 predicate madIds(string madId) {
exists(string model |
PathGraph::edges(_, _, _, model) and
model.regexpFind("(?<=MaD:)[0-9]*", _, _) = madId
)
}
private predicate rankedMadIds(string madId, int r) {
madId = rank[r](string madId0 | madIds(madId0) | madId0 order by madId0.toInt())
}
query 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
exists(string s | model1.splitAt("MaD:", i) = s |
model2 = s and i = 0
or
exists(string part, string madId, string rest, int r |
translateModelsPart(model1, part, i - 1) and
madId = s.regexpCapture("([0-9]*)(.*)", 1) and
rest = s.regexpCapture("([0-9]*)(.*)", 2) and
rankedMadIds(madId, r) and
model2 = part + "MaD:" + r + rest
)
)
}
private predicate translateModels(string model1, string model2) {
exists(int i |
translateModelsPart(model1, model2, i) and
not translateModelsPart(model1, _, i + 1)
)
}
query predicate edges(PathNode a, PathNode b, string key, string val) {
exists(string model |
PathGraph::edges(a, b, key, model) and
translateModels(model, val)
)
}
query predicate nodes = PathGraph::nodes/3;
query predicate subpaths = PathGraph::subpaths/4;
}

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -41,7 +41,9 @@ module KindValidation<KindValidationConfigSig Config> {
"database-store", "format-string", "hash-iteration-count", "predicate-injection",
"preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe",
// Go-only currently, but may be shared in the future
"jwt"
"jwt",
// CPP-only currently
"remote-sink"
]
or
this.matches([

View File

@@ -0,0 +1,120 @@
signature module ModelPrintingLangSig {
/**
* A class of callables.
*/
class Callable;
/**
* Holds if `container`, `type`, `name`, and `parameters` contain the type signature of `api`
* and `extensible` is the string representation of a boolean that is true, if
* `api` can be overridden (otherwise false).
*/
predicate partialModel(
Callable api, string container, string type, string extensible, string name, string parameters
);
}
module ModelPrintingImpl<ModelPrintingLangSig Lang> {
signature module ModelPrintingSig {
/**
* The class of APIs relevant for model generation.
*/
class Api extends Lang::Callable {
Lang::Callable lift();
}
/**
* Gets the string representation of the provenance of the models.
*/
string getProvenance();
}
module ModelPrinting<ModelPrintingSig Printing> {
/**
* Computes the first 6 columns for MaD rows used for summaries, sources and sinks.
*/
private string asPartialModel(Printing::Api api) {
exists(string container, string type, string extensible, string name, string parameters |
Lang::partialModel(api.lift(), container, type, extensible, name, parameters) and
result =
container + ";" //
+ type + ";" //
+ extensible + ";" //
+ name + ";" //
+ parameters + ";" //
+ /* ext + */ ";" //
)
}
/**
* Computes the first 4 columns for neutral MaD rows.
*/
private string asPartialNeutralModel(Printing::Api api) {
exists(string container, string type, string name, string parameters |
Lang::partialModel(api, container, type, _, name, parameters) and
result =
container + ";" //
+ type + ";" //
+ name + ";" //
+ parameters + ";" //
)
}
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
bindingset[input, output, kind]
private string asSummaryModel(Printing::Api api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind + ";" //
+ Printing::getProvenance()
}
string asNeutralSummaryModel(Printing::Api api) {
result =
asPartialNeutralModel(api) //
+ "summary" + ";" //
+ Printing::getProvenance()
}
/**
* Gets the value summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asValueModel(Printing::Api api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
/**
* Gets the taint summary model for `api` with `input` and `output`.
*/
bindingset[input, output]
string asTaintModel(Printing::Api api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/
bindingset[input, kind]
string asSinkModel(Printing::Api api, string input, string kind) {
result =
asPartialModel(api) + input + ";" //
+ kind + ";" //
+ Printing::getProvenance()
}
/**
* Gets the source model for `api` with `output` and `kind`.
*/
bindingset[output, kind]
string asSourceModel(Printing::Api api, string output, string kind) {
result =
asPartialModel(api) + output + ";" //
+ kind + ";" //
+ Printing::getProvenance()
}
}
}

View File

@@ -0,0 +1,53 @@
/**
* Provides some simple predicates for models as data related tests using
* inline expectations (as comments in the source code).
*/
signature module InlineMadTestLangSig {
/**
* A base class of callables for modeling.
*/
class Callable;
/**
* Gets a relevant code comment for `c`, if any.
*/
string getComment(Callable c);
}
module InlineMadTestImpl<InlineMadTestLangSig Lang> {
private class Callable = Lang::Callable;
signature module InlineMadTestConfigSig {
/**
* Gets a captured model for `c`, if any.
*/
string getCapturedModel(Callable c);
/**
* Gets the kind of a captured model.
*/
string getKind();
}
module InlineMadTest<InlineMadTestConfigSig Input> {
private string expects(Callable c) {
Lang::getComment(c).regexpCapture(" *(SPURIOUS-)?" + Input::getKind() + "=(.*)", 2) = result
}
query predicate unexpectedModel(string msg) {
exists(Callable c, string flow |
flow = Input::getCapturedModel(c) and
not flow = expects(c) and
msg = "Unexpected " + Input::getKind() + " found: " + flow
)
}
query predicate expectedModel(string msg) {
exists(Callable c, string e |
e = expects(c) and
not e = Input::getCapturedModel(c) and
msg = "Expected " + Input::getKind() + " missing: " + e
)
}
}
}

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.0.15
No user-facing changes.
## 0.0.14
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -801,7 +801,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
input = bb
or
varBlockReachesExt(def, v, bb, input) and
ssaDefReachesThroughBlock(def, input)
ssaDefReachesThroughBlock(def, pragma[only_bind_into](input))
)
}

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.0.15
No user-facing changes.
## 0.0.14
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/threat-models
version: 0.0.15-dev
version: 1.0.2-dev
library: true
groups: shared
dataExtensions:

View File

@@ -0,0 +1,16 @@
load("@ruby_deps//:defs.bzl", "aliases", "all_crate_deps")
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "codeql-extractor",
srcs = glob([
"src/**/*.rs",
]),
aliases = aliases(),
compile_data = [
"src/generator/prefix.dbscheme",
],
deps = all_crate_deps(package_name = "ruby/extractor/codeql-extractor-fake-crate"),
)

View File

@@ -7,8 +7,9 @@ authors = ["GitHub"]
[dependencies]
flate2 = "1.0"
globset = "0.4"
tree-sitter = "0.20"
tree-sitter = ">= 0.22.6"
tracing = "0.1"
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
rayon = "1.5.0"
regex = "1.7.1"
encoding = "0.2"
@@ -20,5 +21,8 @@ num_cpus = "1.14.0"
[dev-dependencies]
tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql" }
tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json" }
tree-sitter-json = {git = "https://github.com/tree-sitter/tree-sitter-json" }
rand = "0.8.5"
[patch.crates-io]
tree-sitter = {git = "https://github.com/redsun82/tree-sitter.git", rev = "1f5c1112ceaa8fc6aff61d1852690407670d2a96"}

View File

@@ -2,6 +2,6 @@
# extractor. It is set to the lowest version of Rust we want to support.
[toolchain]
channel = "1.68"
channel = "1.74"
profile = "minimal"
components = [ "clippy", "rustfmt" ]

View File

@@ -54,6 +54,12 @@ impl Autobuilder {
let mut cmd = Command::new(codeql);
cmd.arg("database").arg("index-files");
let verbosity = env::var("CODEQL_VERBOSITY");
if let Ok(verbosity) = verbosity {
cmd.arg(format!("--verbosity={}", verbosity));
}
for ext in &self.include_extensions {
cmd.arg(format!("--include-extension={}", ext));
}

View File

@@ -4,12 +4,43 @@ use crate::node_types::{self, EntryKind, Field, NodeTypeMap, Storage, TypeName};
use crate::trap;
use std::collections::BTreeMap as Map;
use std::collections::BTreeSet as Set;
use std::env;
use std::path::Path;
use tree_sitter::{Language, Node, Parser, Range, Tree};
pub mod simple;
/// Sets the tracing level based on the environment variables
/// `RUST_LOG` and `CODEQL_VERBOSITY` (prioritized in that order),
/// falling back to `warn` if neither is set.
pub fn set_tracing_level(language: &str) {
tracing_subscriber::fmt()
.with_target(false)
.without_time()
.with_level(true)
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(
|_| -> tracing_subscriber::EnvFilter {
let verbosity = env::var("CODEQL_VERBOSITY")
.map(|v| match v.to_lowercase().as_str() {
"off" | "errors" => "error",
"warnings" => "warn",
"info" | "progress" => "info",
"debug" | "progress+" => "debug",
"trace" | "progress++" | "progress+++" => "trace",
_ => "warn",
})
.unwrap_or_else(|_| "warn");
tracing_subscriber::EnvFilter::new(format!(
"{language}_extractor={verbosity},codeql_extractor={verbosity}"
))
},
),
)
.init();
}
pub fn populate_file(writer: &mut trap::Writer, absolute_path: &Path) -> trap::Label {
let (file_label, fresh) = writer.global_id(&trap::full_id_for_file(
&file_paths::normalize_path(absolute_path),
@@ -43,7 +74,7 @@ fn populate_empty_file(writer: &mut trap::Writer) -> trap::Label {
pub fn populate_empty_location(writer: &mut trap::Writer) {
let file_label = populate_empty_file(writer);
global_location(
let loc_label = global_location(
writer,
file_label,
trap::Location {
@@ -53,6 +84,7 @@ pub fn populate_empty_location(writer: &mut trap::Writer) {
end_column: 0,
},
);
writer.add_tuple("empty_location", vec![trap::Arg::Label(loc_label)]);
}
pub fn populate_parent_folders(
@@ -150,7 +182,7 @@ fn location_label(
/// Extracts the source file at `path`, which is assumed to be canonicalized.
pub fn extract(
language: Language,
language: &Language,
language_prefix: &str,
schema: &NodeTypeMap,
diagnostics_writer: &mut diagnostics::LogWriter,

View File

@@ -20,7 +20,7 @@ pub struct Extractor {
pub languages: Vec<LanguageSpec>,
pub trap_dir: PathBuf,
pub source_archive_dir: PathBuf,
pub file_list: PathBuf,
pub file_lists: Vec<PathBuf>,
// Typically constructed via `trap::Compression::from_env`.
// This allow us to report the error using our diagnostics system
// without exposing it to consumers.
@@ -29,6 +29,7 @@ pub struct Extractor {
impl Extractor {
pub fn run(&self) -> std::io::Result<()> {
tracing::info!("Extraction started");
let diagnostics = diagnostics::DiagnosticLoggers::new(&self.prefix);
let mut main_thread_logger = diagnostics.logger();
let num_threads = match crate::options::num_threads() {
@@ -74,7 +75,14 @@ impl Extractor {
.build_global()
.unwrap();
let file_list = File::open(&self.file_list)?;
let file_lists: Vec<File> = self
.file_lists
.iter()
.map(|file_list| {
File::open(file_list)
.unwrap_or_else(|_| panic!("Unable to open file list at {:?}", file_list))
})
.collect();
let mut schemas = vec![];
for lang in &self.languages {
@@ -103,8 +111,10 @@ impl Extractor {
)
};
let lines: std::io::Result<Vec<String>> =
std::io::BufReader::new(file_list).lines().collect();
let lines: std::io::Result<Vec<String>> = file_lists
.iter()
.flat_map(|file_list| std::io::BufReader::new(file_list).lines())
.collect();
let lines = lines?;
lines
@@ -137,7 +147,7 @@ impl Extractor {
let lang = &self.languages[i];
crate::extractor::extract(
lang.ts_language,
&lang.ts_language,
lang.prefix,
&schemas[i],
&mut diagnostics_writer,
@@ -161,7 +171,9 @@ impl Extractor {
let mut trap_writer = trap::Writer::new();
crate::extractor::populate_empty_location(&mut trap_writer);
write_trap(&self.trap_dir, &path, &trap_writer, trap_compression)
let res = write_trap(&self.trap_dir, &path, &trap_writer, trap_compression);
tracing::info!("Extraction complete");
res
}
}

View File

@@ -33,6 +33,12 @@ containerparent(
unique int child: @container ref
);
/*- Empty location -*/
empty_location(
int location: @location_default ref
);
/*- Source location prefix -*/
/**

View File

@@ -30,7 +30,7 @@ fn simple_extractor() {
languages: vec![language],
trap_dir,
source_archive_dir,
file_list,
file_lists: vec![file_list],
trap_compression: Ok(trap::Compression::Gzip),
};

View File

@@ -39,7 +39,7 @@ fn multiple_language_extractor() {
languages: vec![lang_ql, lang_json],
trap_dir,
source_archive_dir,
file_list,
file_lists: vec![file_list],
trap_compression: Ok(trap::Compression::Gzip),
};

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
version: 0.2.16-dev
version: 1.0.2-dev
groups: shared
library: true
warnOnImplicitThis: true

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.0.3
No user-facing changes.
## 0.0.2
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/typos
version: 0.2.16-dev
version: 1.0.2-dev
groups: shared
library: true
warnOnImplicitThis: true

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

@@ -0,0 +1,104 @@
/**
* INTERNAL: This module may be replaced without notice.
*
* Provides a module to create first-class representations of sets of values.
*/
/** The input signature for `MakeSets`. */
signature module MkSetsInputSig {
class Key;
class Value;
Value getAValue(Key k);
int totalorder(Value v);
}
/**
* Given a binary predicate `getAValue`, this module groups the `Value` column
* by `Key` and constructs the corresponding sets of `Value`s as single entities.
*
* The output is a functional predicate, `getValueSet`, such that
* `getValueSet(k).contains(v)` is equivalent to `v = getAValue(k)`, and a
* class, `ValueSet`, that canonically represents a set of `Value`s. In
* particular, if two keys `k1` and `k2` relate to the same set of values, then
* `getValueSet(k1) = getValueSet(k2)`.
*
* If the given `totalorder` is not a total order, then the keys for which we
* cannot order the values cannot be given a canonical representation, and
* instead the key is simply reused as the set representation. This provides a
* reasonable fallback where `getValueSet(k).contains(v)` remains equivalent to
* `v = getAValue(k)`.
*/
module MakeSets<MkSetsInputSig Inp> {
private import Inp
private int totalorderExt(Value v) {
result = 0 and v = getAValue(_) and not exists(totalorder(v))
or
result = totalorder(v)
}
private predicate rankedValue(Key k, Value v, int r) {
v = rank[r](Value v0 | v0 = getAValue(k) | v0 order by totalorderExt(v0))
}
private predicate unordered(Key k) {
strictcount(int r | rankedValue(k, _, r)) != strictcount(getAValue(k))
}
private int maxRank(Key k) { result = max(int r | rankedValue(k, _, r)) and not unordered(k) }
private newtype TValList =
TValListNil() or
TValListCons(Value head, int r, TValList tail) { hasValListCons(_, head, r, tail) } or
TValListUnordered(Key k) { unordered(k) }
private predicate hasValListCons(Key k, Value head, int r, TValList tail) {
rankedValue(k, head, r) and
hasValList(k, r - 1, tail)
}
private predicate hasValList(Key k, int r, TValList l) {
exists(getAValue(k)) and r = 0 and l = TValListNil()
or
exists(Value head, TValList tail |
l = TValListCons(head, r, tail) and
hasValListCons(k, head, r, tail)
)
}
private predicate hasValueSet(Key k, TValList vs) {
hasValList(k, maxRank(k), vs) or vs = TValListUnordered(k)
}
/** A set of `Value`s. */
class ValueSet extends TValList {
ValueSet() { hasValueSet(_, this) }
string toString() {
this instanceof TValListCons and result = "ValueSet"
or
this instanceof TValListUnordered and result = "ValueSetUnordered"
}
private predicate sublist(TValListCons l) {
this = l or
this.sublist(TValListCons(_, _, l))
}
/** Holds if this set contains `v`. */
predicate contains(Value v) {
this.sublist(TValListCons(v, _, _))
or
exists(Key k | this = TValListUnordered(k) and v = getAValue(k))
}
}
/**
* Gets the set of values such that `getValueSet(k).contains(v)` is equivalent
* to `v = getAValue(k)`.
*/
ValueSet getValueSet(Key k) { hasValueSet(k, result) }
}

View File

@@ -1,5 +1,5 @@
name: codeql/util
version: 0.2.16-dev
version: 1.0.2-dev
groups: shared
library: true
dependencies: null

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.0.3
No user-facing changes.
## 0.0.2
No user-facing changes.

View File

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

View File

@@ -0,0 +1,5 @@
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,17 @@
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.2.16
No user-facing changes.
## 0.2.15
No user-facing changes.

Some files were not shown because too many files have changed in this diff Show More