mirror of
https://github.com/github/codeql.git
synced 2025-12-22 03:36:30 +01:00
Data flow: Sync files
This commit is contained in:
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1647,9 +1647,6 @@ abstract private class AccessPath extends TAccessPath {
|
|||||||
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
* Holds if this access path has `head` at the front and may be followed by `tail`.
|
||||||
*/
|
*/
|
||||||
abstract predicate pop(Content head, AccessPath tail);
|
abstract predicate pop(Content head, AccessPath tail);
|
||||||
|
|
||||||
/** Gets the untyped version of this access path. */
|
|
||||||
UntypedAccessPath getUntyped() { result.getATyped() = this }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPathNil extends AccessPath, TNil {
|
private class AccessPathNil extends AccessPath, TNil {
|
||||||
@@ -2001,50 +1998,10 @@ private Configuration unbind(Configuration conf) { result >= conf and result <=
|
|||||||
|
|
||||||
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) }
|
||||||
|
|
||||||
private newtype TUntypedAccessPath =
|
|
||||||
TNilUntyped() or
|
|
||||||
TConsNilUntyped(Content f) { exists(TConsNil(f, _)) } or
|
|
||||||
TConsConsUntyped(Content f1, Content f2, int len) { exists(TConsCons(f1, f2, len)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An untyped access path.
|
|
||||||
*
|
|
||||||
* Untyped access paths are only used when reconstructing flow summaries,
|
|
||||||
* where the extra type information is redundant.
|
|
||||||
*/
|
|
||||||
private class UntypedAccessPath extends TUntypedAccessPath {
|
|
||||||
/** Gets a typed version of this untyped access path. */
|
|
||||||
AccessPath getATyped() {
|
|
||||||
this = TNilUntyped() and result = TNil(_)
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = TConsNil(f, _))
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
result = TConsCons(f1, f2, len)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() {
|
|
||||||
this = TNilUntyped() and
|
|
||||||
result = "<nil>"
|
|
||||||
or
|
|
||||||
exists(Content f | this = TConsNilUntyped(f) | result = "[" + f + "]")
|
|
||||||
or
|
|
||||||
exists(Content f1, Content f2, int len | this = TConsConsUntyped(f1, f2, len) |
|
|
||||||
if len = 2
|
|
||||||
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
|
|
||||||
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParameterNode p, UntypedAccessPath uap) {
|
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap |
|
exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) |
|
||||||
ap = uap.getATyped() and
|
|
||||||
flow(TNormalNode(p), true, ap, config)
|
|
||||||
|
|
|
||||||
exists(Summary summary |
|
exists(Summary summary |
|
||||||
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
parameterFlowReturn(p, ret, _, _, _, summary, config) and
|
||||||
flow(ret, unbind(config))
|
flow(ret, unbind(config))
|
||||||
@@ -2080,12 +2037,30 @@ private newtype TSummaryCtx =
|
|||||||
*
|
*
|
||||||
* Summaries are only created for parameters that may flow through.
|
* Summaries are only created for parameters that may flow through.
|
||||||
*/
|
*/
|
||||||
private class SummaryCtx extends TSummaryCtx {
|
abstract private class SummaryCtx extends TSummaryCtx {
|
||||||
string toString() { result = "SummaryCtx" }
|
abstract string toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A summary context from which no flow summary can be generated. */
|
/** A summary context from which no flow summary can be generated. */
|
||||||
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { }
|
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||||
|
override string toString() { result = "<none>" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A summary context from which a flow summary can be generated. */
|
||||||
|
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||||
|
private ParameterNode p;
|
||||||
|
private AccessPath ap;
|
||||||
|
|
||||||
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
|
override string toString() { result = p + ": " + ap }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TPathNode =
|
private newtype TPathNode =
|
||||||
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) {
|
||||||
@@ -2399,22 +2374,22 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, UntypedAccessPath ap
|
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap
|
||||||
) {
|
) {
|
||||||
exists(ArgumentNode arg |
|
exists(ArgumentNode arg |
|
||||||
arg = mid.getNode() and
|
arg = mid.getNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, i) and
|
||||||
ap = mid.getAp().getUntyped()
|
ap = mid.getAp()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, UntypedAccessPath ap, Configuration config
|
DataFlowCallable callable, int i, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParameterNode p |
|
exists(ParameterNode p |
|
||||||
flow(TNormalNode(p), _, ap.getATyped(), config) and
|
flow(TNormalNode(p), _, ap, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2397,7 @@ private predicate parameterCand(
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||||
UntypedAccessPath ap
|
AccessPath ap
|
||||||
) {
|
) {
|
||||||
pathIntoArg(mid, i, outercc, call, ap) and
|
pathIntoArg(mid, i, outercc, call, ap) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
@@ -2438,7 +2413,7 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call
|
DataFlowCall call
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, UntypedAccessPath ap |
|
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
(
|
||||||
@@ -2457,7 +2432,7 @@ private predicate pathIntoCallable(
|
|||||||
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate paramFlowsThrough(
|
private predicate paramFlowsThrough(
|
||||||
ReturnKindExt kind, CallContextCall cc, TSummaryCtxSome sc, AccessPath ap, Configuration config
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, ReturnNodeExt ret |
|
exists(PathNodeMid mid, ReturnNodeExt ret |
|
||||||
mid.getNode() = ret and
|
mid.getNode() = ret and
|
||||||
@@ -2635,14 +2610,7 @@ private module FlowExploration {
|
|||||||
|
|
||||||
private newtype TSummaryCtx2 =
|
private newtype TSummaryCtx2 =
|
||||||
TSummaryCtx2None() or
|
TSummaryCtx2None() or
|
||||||
TSummaryCtx2Nil() or
|
TSummaryCtx2Some(PartialAccessPath ap)
|
||||||
TSummaryCtx2ConsNil(Content f)
|
|
||||||
|
|
||||||
private TSummaryCtx2 getSummaryCtx2(PartialAccessPath ap) {
|
|
||||||
result = TSummaryCtx2Nil() and ap instanceof PartialAccessPathNil
|
|
||||||
or
|
|
||||||
exists(Content f | result = TSummaryCtx2ConsNil(f) and ap = TPartialCons(f, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TPartialPathNode =
|
private newtype TPartialPathNode =
|
||||||
TPartialPathNodeMk(
|
TPartialPathNodeMk(
|
||||||
@@ -2929,11 +2897,8 @@ private module FlowExploration {
|
|||||||
exists(int i, DataFlowCallable callable |
|
exists(int i, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, i) and
|
||||||
(
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc1 = TSummaryCtx1Param(p) and sc2 = getSummaryCtx2(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
or
|
|
||||||
sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and not exists(getSummaryCtx2(ap))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
if recordDataFlowCallSite(call, callable)
|
if recordDataFlowCallSite(call, callable)
|
||||||
then innercc = TSpecificCall(call)
|
then innercc = TSpecificCall(call)
|
||||||
@@ -2953,8 +2918,7 @@ private module FlowExploration {
|
|||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
config = mid.getConfiguration() and
|
config = mid.getConfiguration() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp()
|
||||||
ap.len() in [0 .. 1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user