Merge branch 'main' into python-add-source-nodes

This commit is contained in:
Taus Brock-Nannestad
2020-11-06 17:12:41 +01:00
213 changed files with 28368 additions and 11440 deletions

View File

@@ -1,3 +1,8 @@
/**
* Provides an extension point for for modeling user-controlled data.
* Such data is often used as data-flow sources in security queries.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
// Need to import since frameworks can extend `RemoteFlowSource::Range`

View File

@@ -44,12 +44,24 @@ class StepSummary extends TStepSummary {
}
}
/** Provides predicates for updating step summaries (`StepSummary`s). */
module StepSummary {
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
cached
predicate step(LocalSourceNode nodeFrom, Node nodeTo, StepSummary summary) {
exists(Node mid | typePreservingStep*(nodeFrom, mid) and smallstep(mid, nodeTo, summary))
}
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*
* Unlike `StepSummary::step`, this predicate does not compress
* type-preserving steps.
*/
predicate smallstep(Node nodeFrom, Node nodeTo, StepSummary summary) {
typePreservingStep(nodeFrom, nodeTo) and
summary = LevelStep()
@@ -290,6 +302,7 @@ class TypeTracker extends TTypeTracker {
}
}
/** Provides predicates for implementing custom `TypeTracker`s. */
module TypeTracker {
/**
* Gets a valid end point of type tracking.

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -118,11 +118,13 @@ class Node extends TNode {
Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
}
/** A data-flow node corresponding to an SSA variable. */
class EssaNode extends Node, TEssaNode {
EssaVariable var;
EssaNode() { this = TEssaNode(var) }
/** Gets the `EssaVariable` represented by this data-flow node. */
EssaVariable getVar() { result = var }
override EssaVariable asVar() { result = var }
@@ -135,11 +137,13 @@ class EssaNode extends Node, TEssaNode {
override Location getLocation() { result = var.getDefinition().getLocation() }
}
/** A data-flow node corresponding to a control-flow node. */
class CfgNode extends Node, TCfgNode {
ControlFlowNode node;
CfgNode() { this = TCfgNode(node) }
/** Gets the `ControlFlowNode` represented by this data-flow node. */
ControlFlowNode getNode() { result = node }
override ControlFlowNode asCfgNode() { result = node }
@@ -365,14 +369,15 @@ class LocalSourceNode extends Node {
}
/**
* A reference contained in an object. This is either a field or a property.
* Algebraic datatype for tracking data content associated with values.
* Content can be collection elements or object attributes.
*/
newtype TContent =
/** An element of a list. */
TListElementContent() or
/** An element of a set. */
TSetElementContent() or
/** An element of a tuple at a specifik index. */
/** An element of a tuple at a specific index. */
TTupleElementContent(int index) { exists(any(TupleNode tn).getElement(index)) } or
/** An element of a dictionary under a specific key. */
TDictionaryElementContent(string key) {
@@ -380,24 +385,32 @@ newtype TContent =
or
key = any(Keyword kw).getArg()
} or
/** An element of a dictionary at any key. */
/** An element of a dictionary under any key. */
TDictionaryElementAnyContent() or
/** An object attribute. */
TAttributeContent(string attr) { attr = any(Attribute a).getName() }
/**
* A data-flow value can have associated content.
* If the value is a collection, it can have elements,
* if it is an object, it can have attribute values.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
string toString() { result = "Content" }
}
/** An element of a list. */
class ListElementContent extends TListElementContent, Content {
override string toString() { result = "List element" }
}
/** An element of a set. */
class SetElementContent extends TSetElementContent, Content {
override string toString() { result = "Set element" }
}
/** An element of a tuple at a specific index. */
class TupleElementContent extends TTupleElementContent, Content {
int index;
@@ -409,6 +422,7 @@ class TupleElementContent extends TTupleElementContent, Content {
override string toString() { result = "Tuple element at index " + index.toString() }
}
/** An element of a dictionary under a specific key. */
class DictionaryElementContent extends TDictionaryElementContent, Content {
string key;
@@ -420,10 +434,12 @@ class DictionaryElementContent extends TDictionaryElementContent, Content {
override string toString() { result = "Dictionary element at key " + key }
}
/** An element of a dictionary under any key. */
class DictionaryElementAnyContent extends TDictionaryElementAnyContent, Content {
override string toString() { result = "Any dictionary element" }
}
/** An object attribute. */
class AttributeContent extends TAttributeContent, Content {
private string attr;

View File

@@ -446,7 +446,6 @@ private module SsaComputeImpl {
* ```
*/
pragma[nomagic]
cached
private predicate adjacentRefUse(
SsaSourceVariable v, BasicBlock b2, int i2, ControlFlowNode use1
) {

View File

@@ -629,8 +629,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponse")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponse` alias
// Handle `django.http.HttpResponse` alias
t.start() and
result = http_attr("HttpResponse")
or
@@ -670,7 +669,7 @@ private module Django {
result.asCfgNode() in [node.getArg(1), node.getArgByName("content_type")]
}
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponse`. */
@@ -700,8 +699,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseRedirect")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseRedirect` alias
// Handle `django.http.HttpResponseRedirect` alias
t.start() and
result = http_attr("HttpResponseRedirect")
or
@@ -732,13 +730,16 @@ private module Django {
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
override DataFlow::Node getBody() {
result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")]
// note that even though browsers like Chrome usually doesn't fetch the
// content of a redirect, it is possible to observe the body (for example,
// with cURL).
result.asCfgNode() in [node.getArg(1), node.getArgByName("content")]
}
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseRedirect`. */
@@ -764,8 +765,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponsePermanentRedirect")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponsePermanentRedirect` alias
// Handle `django.http.HttpResponsePermanentRedirect` alias
t.start() and
result = http_attr("HttpResponsePermanentRedirect")
or
@@ -796,13 +796,16 @@ private module Django {
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
override DataFlow::Node getBody() {
result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")]
// note that even though browsers like Chrome usually doesn't fetch the
// content of a redirect, it is possible to observe the body (for example,
// with cURL).
result.asCfgNode() in [node.getArg(1), node.getArgByName("content")]
}
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponsePermanentRedirect`. */
@@ -829,7 +832,7 @@ private module Django {
result = response_attr("HttpResponseNotModified")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseNotModified` alias
// Handle `django.http.HttpResponseNotModified` alias
t.start() and
result = http_attr("HttpResponseNotModified")
or
@@ -890,8 +893,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseBadRequest")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseBadRequest` alias
// Handle `django.http.HttpResponseBadRequest` alias
t.start() and
result = http_attr("HttpResponseBadRequest")
or
@@ -928,7 +930,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseBadRequest`. */
@@ -954,8 +956,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseNotFound")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseNotFound` alias
// Handle `django.http.HttpResponseNotFound` alias
t.start() and
result = http_attr("HttpResponseNotFound")
or
@@ -992,7 +993,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseNotFound`. */
@@ -1018,8 +1019,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseForbidden")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseForbidden` alias
// Handle `django.http.HttpResponseForbidden` alias
t.start() and
result = http_attr("HttpResponseForbidden")
or
@@ -1056,7 +1056,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseForbidden`. */
@@ -1082,8 +1082,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseNotAllowed")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseNotAllowed` alias
// Handle `django.http.HttpResponseNotAllowed` alias
t.start() and
result = http_attr("HttpResponseNotAllowed")
or
@@ -1121,7 +1120,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseNotAllowed`. */
@@ -1147,8 +1146,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseGone")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseGone` alias
// Handle `django.http.HttpResponseGone` alias
t.start() and
result = http_attr("HttpResponseGone")
or
@@ -1185,7 +1183,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseGone`. */
@@ -1211,8 +1209,7 @@ private module Django {
t.start() and
result = response_attr("HttpResponseServerError")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.HttpResponseServerError` alias
// Handle `django.http.HttpResponseServerError` alias
t.start() and
result = http_attr("HttpResponseServerError")
or
@@ -1249,7 +1246,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.HttpResponseServerError`. */
@@ -1275,8 +1272,7 @@ private module Django {
t.start() and
result = response_attr("JsonResponse")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.JsonResponse` alias
// Handle `django.http.JsonResponse` alias
t.start() and
result = http_attr("JsonResponse")
or
@@ -1342,8 +1338,7 @@ private module Django {
t.start() and
result = response_attr("StreamingHttpResponse")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.StreamingHttpResponse` alias
// Handle `django.http.StreamingHttpResponse` alias
t.start() and
result = http_attr("StreamingHttpResponse")
or
@@ -1380,7 +1375,7 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() { result = "text/html" }
}
/** Gets a reference to an instance of `django.http.response.StreamingHttpResponse`. */
@@ -1406,8 +1401,7 @@ private module Django {
t.start() and
result = response_attr("FileResponse")
or
// TODO: remove/expand this part of the template as needed
// Handle `http.FileResponse` alias
// Handle `django.http.FileResponse` alias
t.start() and
result = http_attr("FileResponse")
or
@@ -1444,7 +1438,10 @@ private module Django {
// How to support the `headers` argument here?
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { result = "text/html; charset=utf-8" }
override string getMimetypeDefault() {
// see https://github.com/django/django/blob/ebb08d19424c314c75908bc6048ff57c2f872269/django/http/response.py#L471-L479
result = "application/octet-stream"
}
}
/** Gets a reference to an instance of `django.http.response.FileResponse`. */

View File

@@ -32,6 +32,7 @@ module MySQLdb {
/** Gets a reference to the `MySQLdb` module. */
DataFlow::Node moduleMySQLdb() { result = moduleMySQLdb(DataFlow::TypeTracker::end()) }
/** MySQLdb implements PEP 249, providing ways to execute SQL statements against a database. */
class MySQLdb extends PEP249Module {
MySQLdb() { this = moduleMySQLdb() }
}

View File

@@ -6,6 +6,12 @@ private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
/**
* Provides models for the `Werkzeug` PyPI package.
* See
* - https://pypi.org/project/Werkzeug/
* - https://werkzeug.palletsprojects.com/en/1.0.x/#werkzeug
*/
module Werkzeug {
/** Provides models for the `werkzeug` module. */
module werkzeug {