mirror of
https://github.com/github/codeql.git
synced 2026-07-20 10:48:17 +02:00
Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams
This commit is contained in:
@@ -46,3 +46,5 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
|
||||
the following improvements:
|
||||
* The library now models data flow through `strdup` and similar functions.
|
||||
* The library now models data flow through formatting functions such as `sprintf`.
|
||||
* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, improving the results of many security queries.
|
||||
* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
## General improvements
|
||||
|
||||
* TypeScript 3.8 is now supported.
|
||||
|
||||
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`).
|
||||
|
||||
* Imports with the `.js` extension can now be resolved to a TypeScript file,
|
||||
@@ -13,6 +15,10 @@
|
||||
|
||||
* The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
|
||||
|
||||
* The call graph construction has been improved, leading to more results from the security queries:
|
||||
- Calls can now be resolved to indirectly-defined class members in more cases.
|
||||
- Calls through partial invocations such as `.bind` can now be resolved in more cases.
|
||||
|
||||
* Support for the following frameworks and libraries has been improved:
|
||||
- [Electron](https://electronjs.org/)
|
||||
- [Handlebars](https://www.npmjs.com/package/handlebars)
|
||||
|
||||
@@ -222,10 +222,12 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
|
||||
],
|
||||
"C++ IR ValueNumberInternal": [
|
||||
"IR ValueNumberInternal": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll"
|
||||
],
|
||||
"C++ IR ValueNumber": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
private import cpp
|
||||
|
||||
Function viableImpl(Call call) { result = viableCallable(call) }
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -132,16 +132,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `call` passes an implicit or explicit qualifier, i.e., a
|
||||
* `this` parameter.
|
||||
*/
|
||||
predicate callHasQualifier(Call call) {
|
||||
call.hasQualifier()
|
||||
or
|
||||
call.getTarget() instanceof Destructor
|
||||
}
|
||||
|
||||
private newtype TContent =
|
||||
TFieldContent(Field f) or
|
||||
TCollectionContent() or
|
||||
|
||||
@@ -345,6 +345,7 @@ private Element adjustedSink(DataFlow::Node sink) {
|
||||
result.(AssignOperation).getAnOperand() = sink.asExpr()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate tainted(Expr source, Element tainted) {
|
||||
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(getNodeForSource(source), sink) and
|
||||
@@ -362,6 +363,7 @@ predicate tainted_instruction(
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
|
||||
tainted(source, tainted) and
|
||||
globalVar = ""
|
||||
|
||||
@@ -3,8 +3,6 @@ private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
|
||||
Function viableImpl(CallInstruction call) { result = viableCallable(call) }
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -122,16 +122,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `call` passes an implicit or explicit qualifier, i.e., a
|
||||
* `this` parameter.
|
||||
*/
|
||||
predicate callHasQualifier(Call call) {
|
||||
call.hasQualifier()
|
||||
or
|
||||
call.getTarget() instanceof Destructor
|
||||
}
|
||||
|
||||
private newtype TContent =
|
||||
TFieldContent(Field f) or
|
||||
TCollectionContent() or
|
||||
|
||||
@@ -266,6 +266,16 @@ module InstructionSanity {
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber {
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
@@ -15,7 +14,7 @@ newtype TValueNumber =
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
@@ -33,7 +32,8 @@ newtype TValueNumber =
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
predicate constantValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
|
||||
@@ -266,6 +266,16 @@ module InstructionSanity {
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber {
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
@@ -15,7 +14,7 @@ newtype TValueNumber =
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
@@ -33,7 +32,8 @@ newtype TValueNumber =
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
predicate constantValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
|
||||
@@ -102,6 +102,19 @@ private module Cached {
|
||||
result = getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-phi instruction that defines an operand of `instr` but only if
|
||||
* both `instr` and the result have neighbor on the other side of the edge
|
||||
* between them. This is a necessary condition for being in a cycle, and it
|
||||
* removes about two thirds of the tuples that would otherwise be in this
|
||||
* predicate.
|
||||
*/
|
||||
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
|
||||
result = getNonPhiOperandDef(instr) and
|
||||
exists(getNonPhiOperandDef(result)) and
|
||||
instr = getNonPhiOperandDef(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
@@ -115,7 +128,7 @@ private module Cached {
|
||||
cached
|
||||
predicate isInCycle(Instruction instr) {
|
||||
instr instanceof Instruction and
|
||||
getNonPhiOperandDef+(instr) = instr
|
||||
getNonPhiOperandDefOfIntermediate+(instr) = instr
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -655,6 +655,11 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
kind = getCaseEdge(switchCase) and
|
||||
result = getTranslatedStmt(switchCase).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
not stmt.hasDefaultCase() and
|
||||
tag = SwitchBranchTag() and
|
||||
kind instanceof DefaultEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
|
||||
@@ -266,6 +266,16 @@ module InstructionSanity {
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber {
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
@@ -15,7 +14,7 @@ newtype TValueNumber =
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
@@ -33,7 +32,8 @@ newtype TValueNumber =
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
predicate constantValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
|
||||
@@ -13,6 +13,10 @@ class Function = Cpp::Function;
|
||||
|
||||
class Location = Cpp::Location;
|
||||
|
||||
class UnknownLocation = Cpp::UnknownLocation;
|
||||
|
||||
class UnknownDefaultLocation = Cpp::UnknownDefaultLocation;
|
||||
|
||||
class File = Cpp::File;
|
||||
|
||||
class AST = Cpp::Locatable;
|
||||
|
||||
@@ -80,7 +80,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int i) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
|
||||
@@ -18,14 +18,18 @@ abstract class SideEffectFunction extends Function {
|
||||
/**
|
||||
* Holds if the function never reads from memory that was defined before entry to the function.
|
||||
* This memory could be from global variables, or from other memory that was reachable from a
|
||||
* pointer that was passed into the function.
|
||||
* pointer that was passed into the function. Input side-effects, and reads from memory that
|
||||
* cannot be visible to the caller (for example a buffer inside an I/O library) are not modeled
|
||||
* here.
|
||||
*/
|
||||
abstract predicate hasOnlySpecificReadSideEffects();
|
||||
|
||||
/**
|
||||
* Holds if the function never writes to memory that remains allocated after the function
|
||||
* returns. This memory could be from global variables, or from other memory that was reachable
|
||||
* from a pointer that was passed into the function.
|
||||
* from a pointer that was passed into the function. Output side-effects, and writes to memory
|
||||
* that cannot be visible to the caller (for example a buffer inside an I/O library) are not
|
||||
* modeled here.
|
||||
*/
|
||||
abstract predicate hasOnlySpecificWriteSideEffects();
|
||||
|
||||
@@ -43,7 +47,6 @@ abstract class SideEffectFunction extends Function {
|
||||
*/
|
||||
predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() }
|
||||
|
||||
// TODO: name?
|
||||
/**
|
||||
* Gets the index of the parameter that indicates the size of the buffer pointed to by the
|
||||
* parameter at index `i`.
|
||||
|
||||
@@ -15,27 +15,39 @@
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
import semmle.code.cpp.security.TaintTrackingImpl
|
||||
|
||||
from Expr source, Element tainted, string globalVar
|
||||
where
|
||||
|
||||
@@ -8070,6 +8070,239 @@ ir.cpp:
|
||||
# 1170| Type = [ArrayType] const char[4]
|
||||
# 1170| Value = [StringLiteral] "foo"
|
||||
# 1170| ValueCategory = lvalue
|
||||
# 1173| [TopLevelFunction] void switch1Case(int)
|
||||
# 1173| params:
|
||||
# 1173| 0: [Parameter] x
|
||||
# 1173| Type = [IntType] int
|
||||
# 1173| body: [Block] { ... }
|
||||
# 1174| 0: [DeclStmt] declaration
|
||||
# 1174| 0: [VariableDeclarationEntry] definition of y
|
||||
# 1174| Type = [IntType] int
|
||||
# 1174| init: [Initializer] initializer for y
|
||||
# 1174| expr: [Literal] 0
|
||||
# 1174| Type = [IntType] int
|
||||
# 1174| Value = [Literal] 0
|
||||
# 1174| ValueCategory = prvalue
|
||||
# 1175| 1: [SwitchStmt] switch (...) ...
|
||||
# 1175| 0: [VariableAccess] x
|
||||
# 1175| Type = [IntType] int
|
||||
# 1175| ValueCategory = prvalue(load)
|
||||
# 1175| 1: [Block] { ... }
|
||||
# 1176| 0: [SwitchCase] case ...:
|
||||
# 1176| 0: [Literal] 1
|
||||
# 1176| Type = [IntType] int
|
||||
# 1176| Value = [Literal] 1
|
||||
# 1176| ValueCategory = prvalue
|
||||
# 1177| 1: [ExprStmt] ExprStmt
|
||||
# 1177| 0: [AssignExpr] ... = ...
|
||||
# 1177| Type = [IntType] int
|
||||
# 1177| ValueCategory = lvalue
|
||||
# 1177| 0: [VariableAccess] y
|
||||
# 1177| Type = [IntType] int
|
||||
# 1177| ValueCategory = lvalue
|
||||
# 1177| 1: [Literal] 2
|
||||
# 1177| Type = [IntType] int
|
||||
# 1177| Value = [Literal] 2
|
||||
# 1177| ValueCategory = prvalue
|
||||
# 1179| 2: [DeclStmt] declaration
|
||||
# 1179| 0: [VariableDeclarationEntry] definition of z
|
||||
# 1179| Type = [IntType] int
|
||||
# 1179| init: [Initializer] initializer for z
|
||||
# 1179| expr: [VariableAccess] y
|
||||
# 1179| Type = [IntType] int
|
||||
# 1179| ValueCategory = prvalue(load)
|
||||
# 1180| 3: [ReturnStmt] return ...
|
||||
# 1182| [TopLevelFunction] void switch2Case_fallthrough(int)
|
||||
# 1182| params:
|
||||
# 1182| 0: [Parameter] x
|
||||
# 1182| Type = [IntType] int
|
||||
# 1182| body: [Block] { ... }
|
||||
# 1183| 0: [DeclStmt] declaration
|
||||
# 1183| 0: [VariableDeclarationEntry] definition of y
|
||||
# 1183| Type = [IntType] int
|
||||
# 1183| init: [Initializer] initializer for y
|
||||
# 1183| expr: [Literal] 0
|
||||
# 1183| Type = [IntType] int
|
||||
# 1183| Value = [Literal] 0
|
||||
# 1183| ValueCategory = prvalue
|
||||
# 1184| 1: [SwitchStmt] switch (...) ...
|
||||
# 1184| 0: [VariableAccess] x
|
||||
# 1184| Type = [IntType] int
|
||||
# 1184| ValueCategory = prvalue(load)
|
||||
# 1184| 1: [Block] { ... }
|
||||
# 1185| 0: [SwitchCase] case ...:
|
||||
# 1185| 0: [Literal] 1
|
||||
# 1185| Type = [IntType] int
|
||||
# 1185| Value = [Literal] 1
|
||||
# 1185| ValueCategory = prvalue
|
||||
# 1186| 1: [ExprStmt] ExprStmt
|
||||
# 1186| 0: [AssignExpr] ... = ...
|
||||
# 1186| Type = [IntType] int
|
||||
# 1186| ValueCategory = lvalue
|
||||
# 1186| 0: [VariableAccess] y
|
||||
# 1186| Type = [IntType] int
|
||||
# 1186| ValueCategory = lvalue
|
||||
# 1186| 1: [Literal] 2
|
||||
# 1186| Type = [IntType] int
|
||||
# 1186| Value = [Literal] 2
|
||||
# 1186| ValueCategory = prvalue
|
||||
# 1187| 2: [SwitchCase] case ...:
|
||||
# 1187| 0: [Literal] 2
|
||||
# 1187| Type = [IntType] int
|
||||
# 1187| Value = [Literal] 2
|
||||
# 1187| ValueCategory = prvalue
|
||||
# 1188| 3: [ExprStmt] ExprStmt
|
||||
# 1188| 0: [AssignExpr] ... = ...
|
||||
# 1188| Type = [IntType] int
|
||||
# 1188| ValueCategory = lvalue
|
||||
# 1188| 0: [VariableAccess] y
|
||||
# 1188| Type = [IntType] int
|
||||
# 1188| ValueCategory = lvalue
|
||||
# 1188| 1: [Literal] 3
|
||||
# 1188| Type = [IntType] int
|
||||
# 1188| Value = [Literal] 3
|
||||
# 1188| ValueCategory = prvalue
|
||||
# 1190| 2: [DeclStmt] declaration
|
||||
# 1190| 0: [VariableDeclarationEntry] definition of z
|
||||
# 1190| Type = [IntType] int
|
||||
# 1190| init: [Initializer] initializer for z
|
||||
# 1190| expr: [VariableAccess] y
|
||||
# 1190| Type = [IntType] int
|
||||
# 1190| ValueCategory = prvalue(load)
|
||||
# 1191| 3: [ReturnStmt] return ...
|
||||
# 1193| [TopLevelFunction] void switch2Case(int)
|
||||
# 1193| params:
|
||||
# 1193| 0: [Parameter] x
|
||||
# 1193| Type = [IntType] int
|
||||
# 1193| body: [Block] { ... }
|
||||
# 1194| 0: [DeclStmt] declaration
|
||||
# 1194| 0: [VariableDeclarationEntry] definition of y
|
||||
# 1194| Type = [IntType] int
|
||||
# 1194| init: [Initializer] initializer for y
|
||||
# 1194| expr: [Literal] 0
|
||||
# 1194| Type = [IntType] int
|
||||
# 1194| Value = [Literal] 0
|
||||
# 1194| ValueCategory = prvalue
|
||||
# 1195| 1: [SwitchStmt] switch (...) ...
|
||||
# 1195| 0: [VariableAccess] x
|
||||
# 1195| Type = [IntType] int
|
||||
# 1195| ValueCategory = prvalue(load)
|
||||
# 1195| 1: [Block] { ... }
|
||||
# 1196| 0: [SwitchCase] case ...:
|
||||
# 1196| 0: [Literal] 1
|
||||
# 1196| Type = [IntType] int
|
||||
# 1196| Value = [Literal] 1
|
||||
# 1196| ValueCategory = prvalue
|
||||
# 1197| 1: [ExprStmt] ExprStmt
|
||||
# 1197| 0: [AssignExpr] ... = ...
|
||||
# 1197| Type = [IntType] int
|
||||
# 1197| ValueCategory = lvalue
|
||||
# 1197| 0: [VariableAccess] y
|
||||
# 1197| Type = [IntType] int
|
||||
# 1197| ValueCategory = lvalue
|
||||
# 1197| 1: [Literal] 2
|
||||
# 1197| Type = [IntType] int
|
||||
# 1197| Value = [Literal] 2
|
||||
# 1197| ValueCategory = prvalue
|
||||
# 1198| 2: [BreakStmt] break;
|
||||
# 1199| 3: [SwitchCase] case ...:
|
||||
# 1199| 0: [Literal] 2
|
||||
# 1199| Type = [IntType] int
|
||||
# 1199| Value = [Literal] 2
|
||||
# 1199| ValueCategory = prvalue
|
||||
# 1200| 4: [ExprStmt] ExprStmt
|
||||
# 1200| 0: [AssignExpr] ... = ...
|
||||
# 1200| Type = [IntType] int
|
||||
# 1200| ValueCategory = lvalue
|
||||
# 1200| 0: [VariableAccess] y
|
||||
# 1200| Type = [IntType] int
|
||||
# 1200| ValueCategory = lvalue
|
||||
# 1200| 1: [Literal] 3
|
||||
# 1200| Type = [IntType] int
|
||||
# 1200| Value = [Literal] 3
|
||||
# 1200| ValueCategory = prvalue
|
||||
# 1201| 2: [LabelStmt] label ...:
|
||||
# 1202| 3: [DeclStmt] declaration
|
||||
# 1202| 0: [VariableDeclarationEntry] definition of z
|
||||
# 1202| Type = [IntType] int
|
||||
# 1202| init: [Initializer] initializer for z
|
||||
# 1202| expr: [VariableAccess] y
|
||||
# 1202| Type = [IntType] int
|
||||
# 1202| ValueCategory = prvalue(load)
|
||||
# 1203| 4: [ReturnStmt] return ...
|
||||
# 1205| [TopLevelFunction] void switch2Case_default(int)
|
||||
# 1205| params:
|
||||
# 1205| 0: [Parameter] x
|
||||
# 1205| Type = [IntType] int
|
||||
# 1205| body: [Block] { ... }
|
||||
# 1206| 0: [DeclStmt] declaration
|
||||
# 1206| 0: [VariableDeclarationEntry] definition of y
|
||||
# 1206| Type = [IntType] int
|
||||
# 1206| init: [Initializer] initializer for y
|
||||
# 1206| expr: [Literal] 0
|
||||
# 1206| Type = [IntType] int
|
||||
# 1206| Value = [Literal] 0
|
||||
# 1206| ValueCategory = prvalue
|
||||
# 1207| 1: [SwitchStmt] switch (...) ...
|
||||
# 1207| 0: [VariableAccess] x
|
||||
# 1207| Type = [IntType] int
|
||||
# 1207| ValueCategory = prvalue(load)
|
||||
# 1207| 1: [Block] { ... }
|
||||
# 1208| 0: [SwitchCase] case ...:
|
||||
# 1208| 0: [Literal] 1
|
||||
# 1208| Type = [IntType] int
|
||||
# 1208| Value = [Literal] 1
|
||||
# 1208| ValueCategory = prvalue
|
||||
# 1209| 1: [ExprStmt] ExprStmt
|
||||
# 1209| 0: [AssignExpr] ... = ...
|
||||
# 1209| Type = [IntType] int
|
||||
# 1209| ValueCategory = lvalue
|
||||
# 1209| 0: [VariableAccess] y
|
||||
# 1209| Type = [IntType] int
|
||||
# 1209| ValueCategory = lvalue
|
||||
# 1209| 1: [Literal] 2
|
||||
# 1209| Type = [IntType] int
|
||||
# 1209| Value = [Literal] 2
|
||||
# 1209| ValueCategory = prvalue
|
||||
# 1210| 2: [BreakStmt] break;
|
||||
# 1212| 3: [SwitchCase] case ...:
|
||||
# 1212| 0: [Literal] 2
|
||||
# 1212| Type = [IntType] int
|
||||
# 1212| Value = [Literal] 2
|
||||
# 1212| ValueCategory = prvalue
|
||||
# 1213| 4: [ExprStmt] ExprStmt
|
||||
# 1213| 0: [AssignExpr] ... = ...
|
||||
# 1213| Type = [IntType] int
|
||||
# 1213| ValueCategory = lvalue
|
||||
# 1213| 0: [VariableAccess] y
|
||||
# 1213| Type = [IntType] int
|
||||
# 1213| ValueCategory = lvalue
|
||||
# 1213| 1: [Literal] 3
|
||||
# 1213| Type = [IntType] int
|
||||
# 1213| Value = [Literal] 3
|
||||
# 1213| ValueCategory = prvalue
|
||||
# 1214| 5: [BreakStmt] break;
|
||||
# 1216| 6: [SwitchCase] default:
|
||||
# 1217| 7: [ExprStmt] ExprStmt
|
||||
# 1217| 0: [AssignExpr] ... = ...
|
||||
# 1217| Type = [IntType] int
|
||||
# 1217| ValueCategory = lvalue
|
||||
# 1217| 0: [VariableAccess] y
|
||||
# 1217| Type = [IntType] int
|
||||
# 1217| ValueCategory = lvalue
|
||||
# 1217| 1: [Literal] 4
|
||||
# 1217| Type = [IntType] int
|
||||
# 1217| Value = [Literal] 4
|
||||
# 1217| ValueCategory = prvalue
|
||||
# 1218| 2: [LabelStmt] label ...:
|
||||
# 1219| 3: [DeclStmt] declaration
|
||||
# 1219| 0: [VariableDeclarationEntry] definition of z
|
||||
# 1219| Type = [IntType] int
|
||||
# 1219| init: [Initializer] initializer for z
|
||||
# 1219| expr: [VariableAccess] y
|
||||
# 1219| Type = [IntType] int
|
||||
# 1219| ValueCategory = prvalue(load)
|
||||
# 1220| 4: [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| params:
|
||||
|
||||
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -1170,4 +1170,53 @@ String ReturnObjectImpl() {
|
||||
return String("foo");
|
||||
}
|
||||
|
||||
void switch1Case(int x) {
|
||||
int y = 0;
|
||||
switch(x) {
|
||||
case 1:
|
||||
y = 2;
|
||||
}
|
||||
int z = y;
|
||||
}
|
||||
|
||||
void switch2Case_fallthrough(int x) {
|
||||
int y = 0;
|
||||
switch(x) {
|
||||
case 1:
|
||||
y = 2;
|
||||
case 2:
|
||||
y = 3;
|
||||
}
|
||||
int z = y;
|
||||
}
|
||||
|
||||
void switch2Case(int x) {
|
||||
int y = 0;
|
||||
switch(x) {
|
||||
case 1:
|
||||
y = 2;
|
||||
break;
|
||||
case 2:
|
||||
y = 3;
|
||||
}
|
||||
int z = y;
|
||||
}
|
||||
|
||||
void switch2Case_default(int x) {
|
||||
int y = 0;
|
||||
switch(x) {
|
||||
case 1:
|
||||
y = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
y = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
y = 4;
|
||||
}
|
||||
int z = y;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -6052,6 +6052,182 @@ ir.cpp:
|
||||
# 1169| v1169_8(void) = AliasedUse : ~mu1169_4
|
||||
# 1169| v1169_9(void) = ExitFunction :
|
||||
|
||||
# 1173| void switch1Case(int)
|
||||
# 1173| Block 0
|
||||
# 1173| v1173_1(void) = EnterFunction :
|
||||
# 1173| mu1173_2(unknown) = AliasedDefinition :
|
||||
# 1173| mu1173_3(unknown) = InitializeNonLocal :
|
||||
# 1173| mu1173_4(unknown) = UnmodeledDefinition :
|
||||
# 1173| r1173_5(glval<int>) = VariableAddress[x] :
|
||||
# 1173| mu1173_6(int) = InitializeParameter[x] : &:r1173_5
|
||||
# 1174| r1174_1(glval<int>) = VariableAddress[y] :
|
||||
# 1174| r1174_2(int) = Constant[0] :
|
||||
# 1174| mu1174_3(int) = Store : &:r1174_1, r1174_2
|
||||
# 1175| r1175_1(glval<int>) = VariableAddress[x] :
|
||||
# 1175| r1175_2(int) = Load : &:r1175_1, ~mu1173_4
|
||||
# 1175| v1175_3(void) = Switch : r1175_2
|
||||
#-----| Case[1] -> Block 1
|
||||
#-----| Default -> Block 2
|
||||
|
||||
# 1176| Block 1
|
||||
# 1176| v1176_1(void) = NoOp :
|
||||
# 1177| r1177_1(int) = Constant[2] :
|
||||
# 1177| r1177_2(glval<int>) = VariableAddress[y] :
|
||||
# 1177| mu1177_3(int) = Store : &:r1177_2, r1177_1
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 1179| Block 2
|
||||
# 1179| r1179_1(glval<int>) = VariableAddress[z] :
|
||||
# 1179| r1179_2(glval<int>) = VariableAddress[y] :
|
||||
# 1179| r1179_3(int) = Load : &:r1179_2, ~mu1173_4
|
||||
# 1179| mu1179_4(int) = Store : &:r1179_1, r1179_3
|
||||
# 1180| v1180_1(void) = NoOp :
|
||||
# 1173| v1173_7(void) = ReturnVoid :
|
||||
# 1173| v1173_8(void) = UnmodeledUse : mu*
|
||||
# 1173| v1173_9(void) = AliasedUse : ~mu1173_4
|
||||
# 1173| v1173_10(void) = ExitFunction :
|
||||
|
||||
# 1182| void switch2Case_fallthrough(int)
|
||||
# 1182| Block 0
|
||||
# 1182| v1182_1(void) = EnterFunction :
|
||||
# 1182| mu1182_2(unknown) = AliasedDefinition :
|
||||
# 1182| mu1182_3(unknown) = InitializeNonLocal :
|
||||
# 1182| mu1182_4(unknown) = UnmodeledDefinition :
|
||||
# 1182| r1182_5(glval<int>) = VariableAddress[x] :
|
||||
# 1182| mu1182_6(int) = InitializeParameter[x] : &:r1182_5
|
||||
# 1183| r1183_1(glval<int>) = VariableAddress[y] :
|
||||
# 1183| r1183_2(int) = Constant[0] :
|
||||
# 1183| mu1183_3(int) = Store : &:r1183_1, r1183_2
|
||||
# 1184| r1184_1(glval<int>) = VariableAddress[x] :
|
||||
# 1184| r1184_2(int) = Load : &:r1184_1, ~mu1182_4
|
||||
# 1184| v1184_3(void) = Switch : r1184_2
|
||||
#-----| Case[1] -> Block 1
|
||||
#-----| Case[2] -> Block 2
|
||||
#-----| Default -> Block 3
|
||||
|
||||
# 1185| Block 1
|
||||
# 1185| v1185_1(void) = NoOp :
|
||||
# 1186| r1186_1(int) = Constant[2] :
|
||||
# 1186| r1186_2(glval<int>) = VariableAddress[y] :
|
||||
# 1186| mu1186_3(int) = Store : &:r1186_2, r1186_1
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 1187| Block 2
|
||||
# 1187| v1187_1(void) = NoOp :
|
||||
# 1188| r1188_1(int) = Constant[3] :
|
||||
# 1188| r1188_2(glval<int>) = VariableAddress[y] :
|
||||
# 1188| mu1188_3(int) = Store : &:r1188_2, r1188_1
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1190| Block 3
|
||||
# 1190| r1190_1(glval<int>) = VariableAddress[z] :
|
||||
# 1190| r1190_2(glval<int>) = VariableAddress[y] :
|
||||
# 1190| r1190_3(int) = Load : &:r1190_2, ~mu1182_4
|
||||
# 1190| mu1190_4(int) = Store : &:r1190_1, r1190_3
|
||||
# 1191| v1191_1(void) = NoOp :
|
||||
# 1182| v1182_7(void) = ReturnVoid :
|
||||
# 1182| v1182_8(void) = UnmodeledUse : mu*
|
||||
# 1182| v1182_9(void) = AliasedUse : ~mu1182_4
|
||||
# 1182| v1182_10(void) = ExitFunction :
|
||||
|
||||
# 1193| void switch2Case(int)
|
||||
# 1193| Block 0
|
||||
# 1193| v1193_1(void) = EnterFunction :
|
||||
# 1193| mu1193_2(unknown) = AliasedDefinition :
|
||||
# 1193| mu1193_3(unknown) = InitializeNonLocal :
|
||||
# 1193| mu1193_4(unknown) = UnmodeledDefinition :
|
||||
# 1193| r1193_5(glval<int>) = VariableAddress[x] :
|
||||
# 1193| mu1193_6(int) = InitializeParameter[x] : &:r1193_5
|
||||
# 1194| r1194_1(glval<int>) = VariableAddress[y] :
|
||||
# 1194| r1194_2(int) = Constant[0] :
|
||||
# 1194| mu1194_3(int) = Store : &:r1194_1, r1194_2
|
||||
# 1195| r1195_1(glval<int>) = VariableAddress[x] :
|
||||
# 1195| r1195_2(int) = Load : &:r1195_1, ~mu1193_4
|
||||
# 1195| v1195_3(void) = Switch : r1195_2
|
||||
#-----| Case[1] -> Block 1
|
||||
#-----| Case[2] -> Block 2
|
||||
#-----| Default -> Block 3
|
||||
|
||||
# 1196| Block 1
|
||||
# 1196| v1196_1(void) = NoOp :
|
||||
# 1197| r1197_1(int) = Constant[2] :
|
||||
# 1197| r1197_2(glval<int>) = VariableAddress[y] :
|
||||
# 1197| mu1197_3(int) = Store : &:r1197_2, r1197_1
|
||||
# 1198| v1198_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1199| Block 2
|
||||
# 1199| v1199_1(void) = NoOp :
|
||||
# 1200| r1200_1(int) = Constant[3] :
|
||||
# 1200| r1200_2(glval<int>) = VariableAddress[y] :
|
||||
# 1200| mu1200_3(int) = Store : &:r1200_2, r1200_1
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1201| Block 3
|
||||
# 1201| v1201_1(void) = NoOp :
|
||||
# 1202| r1202_1(glval<int>) = VariableAddress[z] :
|
||||
# 1202| r1202_2(glval<int>) = VariableAddress[y] :
|
||||
# 1202| r1202_3(int) = Load : &:r1202_2, ~mu1193_4
|
||||
# 1202| mu1202_4(int) = Store : &:r1202_1, r1202_3
|
||||
# 1203| v1203_1(void) = NoOp :
|
||||
# 1193| v1193_7(void) = ReturnVoid :
|
||||
# 1193| v1193_8(void) = UnmodeledUse : mu*
|
||||
# 1193| v1193_9(void) = AliasedUse : ~mu1193_4
|
||||
# 1193| v1193_10(void) = ExitFunction :
|
||||
|
||||
# 1205| void switch2Case_default(int)
|
||||
# 1205| Block 0
|
||||
# 1205| v1205_1(void) = EnterFunction :
|
||||
# 1205| mu1205_2(unknown) = AliasedDefinition :
|
||||
# 1205| mu1205_3(unknown) = InitializeNonLocal :
|
||||
# 1205| mu1205_4(unknown) = UnmodeledDefinition :
|
||||
# 1205| r1205_5(glval<int>) = VariableAddress[x] :
|
||||
# 1205| mu1205_6(int) = InitializeParameter[x] : &:r1205_5
|
||||
# 1206| r1206_1(glval<int>) = VariableAddress[y] :
|
||||
# 1206| r1206_2(int) = Constant[0] :
|
||||
# 1206| mu1206_3(int) = Store : &:r1206_1, r1206_2
|
||||
# 1207| r1207_1(glval<int>) = VariableAddress[x] :
|
||||
# 1207| r1207_2(int) = Load : &:r1207_1, ~mu1205_4
|
||||
# 1207| v1207_3(void) = Switch : r1207_2
|
||||
#-----| Case[1] -> Block 1
|
||||
#-----| Case[2] -> Block 2
|
||||
#-----| Default -> Block 3
|
||||
|
||||
# 1208| Block 1
|
||||
# 1208| v1208_1(void) = NoOp :
|
||||
# 1209| r1209_1(int) = Constant[2] :
|
||||
# 1209| r1209_2(glval<int>) = VariableAddress[y] :
|
||||
# 1209| mu1209_3(int) = Store : &:r1209_2, r1209_1
|
||||
# 1210| v1210_1(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 1212| Block 2
|
||||
# 1212| v1212_1(void) = NoOp :
|
||||
# 1213| r1213_1(int) = Constant[3] :
|
||||
# 1213| r1213_2(glval<int>) = VariableAddress[y] :
|
||||
# 1213| mu1213_3(int) = Store : &:r1213_2, r1213_1
|
||||
# 1214| v1214_1(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 1216| Block 3
|
||||
# 1216| v1216_1(void) = NoOp :
|
||||
# 1217| r1217_1(int) = Constant[4] :
|
||||
# 1217| r1217_2(glval<int>) = VariableAddress[y] :
|
||||
# 1217| mu1217_3(int) = Store : &:r1217_2, r1217_1
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 1218| Block 4
|
||||
# 1218| v1218_1(void) = NoOp :
|
||||
# 1219| r1219_1(glval<int>) = VariableAddress[z] :
|
||||
# 1219| r1219_2(glval<int>) = VariableAddress[y] :
|
||||
# 1219| r1219_3(int) = Load : &:r1219_2, ~mu1205_4
|
||||
# 1219| mu1219_4(int) = Store : &:r1219_1, r1219_3
|
||||
# 1220| v1220_1(void) = NoOp :
|
||||
# 1205| v1205_7(void) = ReturnVoid :
|
||||
# 1205| v1205_8(void) = UnmodeledUse : mu*
|
||||
# 1205| v1205_9(void) = AliasedUse : ~mu1205_4
|
||||
# 1205| v1205_10(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -886,27 +886,25 @@ ssa.cpp:
|
||||
# 199| r199_7(char *) = Load : &:r199_6, m198_11
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_12(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_7
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_12
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_15
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -883,27 +883,25 @@ ssa.cpp:
|
||||
# 199| r199_7(char *) = Load : &:r199_6, m198_11
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_12(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_7
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_12
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_15
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -829,27 +829,25 @@ ssa.cpp:
|
||||
# 199| r199_7(char *) = Load : &:r199_6, m198_10
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
|
||||
# 199| m199_12(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_6
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_12
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_14
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -829,27 +829,25 @@ ssa.cpp:
|
||||
# 199| r199_7(char *) = Load : &:r199_6, m198_10
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
|
||||
# 199| m199_12(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_6
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_12
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_14
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
bodies
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:28:10:3 | { ... } |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:28:30:3 | { ... } |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:27:46:3 | { ... } |
|
||||
variables
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:13:8:17 | value | file://:0:0:0:0 | short |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:12:28:16 | value | file://:0:0:0:0 | int |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:13:44:17 | value | file://:0:0:0:0 | long |
|
||||
ranges
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:21:8:25 | array | file://:0:0:0:0 | short[100] |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:25 | vector | test.cpp:16:8:16:13 | Vector<int> |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:21:44:24 | list | file://:0:0:0:0 | const List<long> & |
|
||||
rangeVariables
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__range) | file://:0:0:0:0 | short(&)[100] |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__range) | file://:0:0:0:0 | Vector<int> & |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__range) | file://:0:0:0:0 | const List<long> & |
|
||||
conditions
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) |
|
||||
beginVariables
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__begin) | file://:0:0:0:0 | short * |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__begin) | test.cpp:17:10:17:17 | Iterator |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__begin) | file://:0:0:0:0 | long * |
|
||||
endVariables
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__end) | file://:0:0:0:0 | short * |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:3:28:3 | (__end) | test.cpp:17:10:17:17 | Iterator |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__end) | file://:0:0:0:0 | long * |
|
||||
updates
|
||||
| test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) |
|
||||
| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | file://:0:0:0:0 | (__begin) |
|
||||
| test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) |
|
||||
52
cpp/ql/test/library-tests/range_based_for/range_based_for.ql
Normal file
52
cpp/ql/test/library-tests/range_based_for/range_based_for.ql
Normal file
@@ -0,0 +1,52 @@
|
||||
import cpp
|
||||
|
||||
query predicate bodies(RangeBasedForStmt rbf, Stmt body) { body = rbf.getStmt() }
|
||||
|
||||
query predicate variables(RangeBasedForStmt rbf, LocalVariable v, Type t) {
|
||||
v = rbf.getVariable() and
|
||||
t = v.getType()
|
||||
}
|
||||
|
||||
query predicate ranges(RangeBasedForStmt rbf, Expr range, Type t) {
|
||||
range = rbf.getRange() and
|
||||
t = range.getType()
|
||||
}
|
||||
|
||||
query predicate rangeVariables(RangeBasedForStmt rbf, LocalVariable rangeVar, Type t) {
|
||||
rangeVar = rbf.getRangeVariable() and
|
||||
t = rangeVar.getType()
|
||||
}
|
||||
|
||||
query predicate conditions(RangeBasedForStmt rbf, Expr condition, Expr left, Expr right) {
|
||||
condition = rbf.getCondition() and
|
||||
(
|
||||
condition instanceof BinaryOperation and
|
||||
left = condition.(BinaryOperation).getLeftOperand() and
|
||||
right = condition.(BinaryOperation).getRightOperand()
|
||||
or
|
||||
condition instanceof FunctionCall and
|
||||
left = condition.(FunctionCall).getQualifier() and
|
||||
right = condition.(FunctionCall).getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate beginVariables(RangeBasedForStmt rbf, LocalVariable beginVar, Type t) {
|
||||
beginVar = rbf.getBeginVariable() and
|
||||
t = beginVar.getType()
|
||||
}
|
||||
|
||||
query predicate endVariables(RangeBasedForStmt rbf, LocalVariable endVar, Type t) {
|
||||
endVar = rbf.getEndVariable() and
|
||||
t = endVar.getType()
|
||||
}
|
||||
|
||||
query predicate updates(RangeBasedForStmt rbf, Expr update, Expr operand) {
|
||||
update = rbf.getUpdate() and
|
||||
(
|
||||
update instanceof UnaryOperation and
|
||||
operand = update.(UnaryOperation).getOperand()
|
||||
or
|
||||
update instanceof FunctionCall and
|
||||
operand = update.(FunctionCall).getQualifier()
|
||||
)
|
||||
}
|
||||
47
cpp/ql/test/library-tests/range_based_for/test.cpp
Normal file
47
cpp/ql/test/library-tests/range_based_for/test.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
void print_short(short);
|
||||
void print_int(int);
|
||||
void print_long(long);
|
||||
|
||||
short array[100];
|
||||
void loop_over_c_array() {
|
||||
for (auto value : array) {
|
||||
print_short(value);
|
||||
}
|
||||
}
|
||||
|
||||
// A class that can be used with range-based-for, because it has the member
|
||||
// functions `begin` and `end`.
|
||||
template<typename T>
|
||||
struct Vector {
|
||||
struct Iterator {
|
||||
const T& operator*() const;
|
||||
bool operator!=(const Iterator &rhs) const;
|
||||
Iterator operator++();
|
||||
};
|
||||
Iterator begin();
|
||||
Iterator end();
|
||||
};
|
||||
|
||||
Vector<int> vector;
|
||||
void loop_over_vector_object() {
|
||||
for (int value : vector) {
|
||||
print_int(value);
|
||||
}
|
||||
}
|
||||
|
||||
// A class that can be used with range-based-for, because there are `begin` and
|
||||
// `end` functions that take a `List` as their argument.
|
||||
template<typename T>
|
||||
struct List {};
|
||||
|
||||
template<typename T>
|
||||
T* begin(const List<T> &list);
|
||||
template<typename T>
|
||||
T* end(const List<T> &list);
|
||||
|
||||
void loop_over_list_object(const List<long> &list) {
|
||||
for (auto value : list) {
|
||||
print_long(value);
|
||||
}
|
||||
}
|
||||
@@ -568,6 +568,7 @@ lostReachability
|
||||
| range_analysis.c:371:37:371:39 | Constant: 500 |
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -645,6 +645,7 @@ useNotDominatedByDefinition
|
||||
| pointer_to_member.cpp:36:22:36:28 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
|
||||
| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) |
|
||||
| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | IR: main | int main(int, char**) |
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -577,6 +577,7 @@ lostReachability
|
||||
| range_analysis.c:371:37:371:39 | Constant: 500 |
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
| test.cpp:5:3:5:3 | GVN | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | GVN | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | GVN | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
| test.cpp:5:12:5:13 | GVN | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | GVN | 16:c3-c3 17:c3-c3 |
|
||||
| test.cpp:16:7:16:8 | GVN | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | GVN | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | GVN | 16:c7-c24 17:c7-c24 18:c7-c7 |
|
||||
| test.cpp:16:12:16:13 | GVN | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | GVN | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:3:29:3 | GVN | 29:c3-c3 31:c3-c3 |
|
||||
| test.cpp:29:7:29:8 | GVN | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | GVN | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:12:29:13 | GVN | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:31:7:31:24 | GVN | 31:c7-c24 32:c7-c7 |
|
||||
| test.cpp:43:3:43:3 | GVN | 43:c3-c3 45:c3-c3 |
|
||||
| test.cpp:43:7:43:8 | GVN | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | GVN | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:7:43:24 | GVN | 43:c7-c24 45:c7-c24 46:c7-c7 |
|
||||
| test.cpp:43:12:43:13 | GVN | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:43:17:43:24 | GVN | 43:c17-c24 45:c17-c24 |
|
||||
| test.cpp:44:3:44:5 | GVN | 44:c3-c5 44:c4-c5 |
|
||||
| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | GVN | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:53:18:53:21 | GVN | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:56:14:56:16 | GVN | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:62:5:62:10 | GVN | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:28 | GVN | 77:c20-c28 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | GVN | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:92:11:92:16 | GVN | 92:c11-c16 92:c15-c16 93:c10-c10 |
|
||||
| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 107:c11-c12 |
|
||||
| test.cpp:105:15:105:15 | GVN | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
| test.cpp:113:3:113:5 | GVN | 113:c3-c5 115:c3-c5 |
|
||||
| test.cpp:125:11:125:12 | GVN | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
|
||||
| test.cpp:125:15:125:15 | GVN | 125:c15-c15 126:c15-c15 |
|
||||
| test.cpp:128:11:128:11 | GVN | 128:c11-c11 129:c15-c15 |
|
||||
| test.cpp:136:11:136:18 | GVN | 136:c11-c18 137:c11-c18 139:c3-c10 |
|
||||
| test.cpp:144:11:144:12 | GVN | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
|
||||
| test.cpp:144:15:144:15 | GVN | 144:c15-c15 149:c15-c15 |
|
||||
| test.cpp:153:11:153:18 | GVN | 153:c11-c18 154:c11-c18 156:c3-c10 |
|
||||
@@ -1,58 +0,0 @@
|
||||
| test.cpp:5:3:5:13 | ... = ... | |
|
||||
| test.cpp:6:3:6:13 | ... = ... | |
|
||||
| test.cpp:7:3:7:7 | ... = ... | |
|
||||
| test.cpp:10:16:10:16 | 1 | |
|
||||
| test.cpp:16:3:16:24 | ... = ... | |
|
||||
| test.cpp:17:3:17:24 | ... = ... | |
|
||||
| test.cpp:18:3:18:7 | ... = ... | |
|
||||
| test.cpp:21:16:21:16 | 2 | |
|
||||
| test.cpp:29:3:29:24 | ... = ... | |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | |
|
||||
| test.cpp:31:3:31:24 | ... = ... | |
|
||||
| test.cpp:32:3:32:7 | ... = ... | |
|
||||
| test.cpp:35:16:35:16 | 3 | |
|
||||
| test.cpp:43:3:43:24 | ... = ... | |
|
||||
| test.cpp:44:3:44:9 | ... = ... | |
|
||||
| test.cpp:45:3:45:24 | ... = ... | |
|
||||
| test.cpp:46:3:46:7 | ... = ... | |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | |
|
||||
| test.cpp:53:10:53:13 | (int)... | |
|
||||
| test.cpp:53:10:53:13 | * ... | LoadTotalOverlap, Unary |
|
||||
| test.cpp:53:18:53:21 | (int)... | |
|
||||
| test.cpp:55:5:55:15 | ... = ... | |
|
||||
| test.cpp:56:12:56:25 | (...) | |
|
||||
| test.cpp:56:12:56:43 | ... && ... | |
|
||||
| test.cpp:56:13:56:16 | (int)... | |
|
||||
| test.cpp:56:13:56:16 | * ... | Unary, Unique |
|
||||
| test.cpp:56:21:56:24 | (int)... | |
|
||||
| test.cpp:56:21:56:24 | * ... | LoadTotalOverlap, Unary |
|
||||
| test.cpp:56:30:56:43 | (...) | |
|
||||
| test.cpp:56:31:56:34 | (int)... | |
|
||||
| test.cpp:56:31:56:34 | * ... | Unary, Unique |
|
||||
| test.cpp:56:39:56:42 | (int)... | |
|
||||
| test.cpp:56:47:56:51 | ... ++ | |
|
||||
| test.cpp:59:9:59:12 | (int)... | |
|
||||
| test.cpp:59:9:59:12 | * ... | Unary, Unique |
|
||||
| test.cpp:59:17:59:20 | (int)... | |
|
||||
| test.cpp:62:5:62:12 | ... ++ | |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | Unary, Unique |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | |
|
||||
| test.cpp:79:7:79:7 | (int)... | |
|
||||
| test.cpp:79:7:79:7 | v | Unary, Unary |
|
||||
| test.cpp:79:11:79:20 | (int)... | |
|
||||
| test.cpp:79:17:79:20 | val1 | LoadTotalOverlap, Unary |
|
||||
| test.cpp:79:24:79:33 | (int)... | |
|
||||
| test.cpp:79:30:79:33 | val2 | LoadTotalOverlap, Unary |
|
||||
| test.cpp:80:5:80:19 | ... = ... | |
|
||||
| test.cpp:80:9:80:17 | call to getAValue | Unary, Unique |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | |
|
||||
| test.cpp:88:3:88:20 | ... = ... | |
|
||||
| test.cpp:88:12:88:12 | (void *)... | |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | |
|
||||
| test.cpp:105:11:105:12 | pd | InheritanceConversion, InitializeParameter |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | |
|
||||
| test.cpp:106:33:106:34 | pd | InheritanceConversion, InitializeParameter |
|
||||
| test.cpp:128:3:128:11 | ... = ... | |
|
||||
| test.cpp:139:3:139:24 | ... = ... | |
|
||||
| test.cpp:147:3:147:18 | ... = ... | |
|
||||
| test.cpp:156:3:156:17 | ... = ... | |
|
||||
@@ -0,0 +1,40 @@
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 |
|
||||
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 18:c7-c7 |
|
||||
| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:31:7:31:24 | ... + ... | 31:c7-c24 32:c7-c7 |
|
||||
| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:44:9:44:9 | 0 | 44:c9-c9 51:c25-c25 53:c18-c21 56:c39-c42 59:c17-c20 88:c12-c12 |
|
||||
| test.cpp:45:7:45:24 | ... + ... | 45:c7-c24 46:c7-c7 |
|
||||
| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:53:18:53:21 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:14:56:16 | ptr | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 |
|
||||
| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
| test.cpp:125:11:125:12 | pa | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
|
||||
| test.cpp:125:15:125:15 | x | 125:c15-c15 126:c15-c15 128:c7-c7 |
|
||||
| test.cpp:136:11:136:18 | global_a | 136:c11-c18 137:c11-c18 139:c3-c10 |
|
||||
| test.cpp:136:21:136:21 | x | 136:c21-c21 137:c21-c21 139:c13-c13 |
|
||||
| test.cpp:144:11:144:12 | pa | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
|
||||
| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 |
|
||||
| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 |
|
||||
| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 |
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
|
||||
|
||||
from GVN g
|
||||
where strictcount(g.getAnExpr()) > 1
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
|
||||
|
||||
// Every expression should have exactly one GVN.
|
||||
// So this query should have zero results.
|
||||
@@ -0,0 +1,142 @@
|
||||
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
|
||||
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
|
||||
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
|
||||
| test.cpp:10:16:10:16 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
|
||||
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
|
||||
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
|
||||
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
|
||||
| test.cpp:21:16:21:16 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
|
||||
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
|
||||
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
|
||||
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
|
||||
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
|
||||
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
|
||||
| test.cpp:35:16:35:16 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
|
||||
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
|
||||
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only |
|
||||
| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only |
|
||||
| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only |
|
||||
| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only |
|
||||
| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only |
|
||||
| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only |
|
||||
| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only |
|
||||
| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only |
|
||||
| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only |
|
||||
| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only |
|
||||
| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
|
||||
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
|
||||
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
|
||||
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
|
||||
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only |
|
||||
| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only |
|
||||
| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only |
|
||||
| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
|
||||
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
|
||||
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only |
|
||||
| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only |
|
||||
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
|
||||
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
|
||||
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
|
||||
| test.cpp:153:21:153:21 | x | test.cpp:154:21:154:21 | x | AST only |
|
||||
| test.cpp:154:21:154:21 | x | test.cpp:153:21:153:21 | x | AST only |
|
||||
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering as AST
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl as AST
|
||||
import semmle.code.cpp.ir.internal.ASTValueNumbering as IR
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
|
||||
@@ -146,19 +146,21 @@ int main(int argc, char **argv) {
|
||||
|
||||
// BAD: i8 value comes from argv
|
||||
char *i8;
|
||||
*(&i8 + 1) = argv[1];
|
||||
*(&i8) = argv[1];
|
||||
printf(i8);
|
||||
printWrapper(i8);
|
||||
|
||||
// BAD: i9 value comes from argv
|
||||
char *i9;
|
||||
memcpy(1 ? i9++ : 0, argv[1], 1);
|
||||
char i9buf[32];
|
||||
char *i9 = i9buf;
|
||||
memcpy(1 ? ++i9 : 0, argv[1], 1);
|
||||
printf(i9);
|
||||
printWrapper(i9);
|
||||
|
||||
// BAD: i91 value comes from argv
|
||||
char *i91;
|
||||
memcpy(0 ? 0 : (char *)((int) i91 * 2), argv[1], 1);
|
||||
char i91buf[64];
|
||||
char *i91 = &i91buf[0];
|
||||
memcpy(0 ? 0 : i91, argv[1] + 1, 1);
|
||||
printf(i91);
|
||||
printWrapper(i91);
|
||||
|
||||
|
||||
@@ -18,5 +18,11 @@
|
||||
| argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
|
||||
| argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
|
||||
| argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
|
||||
| argvLocal.c:167:18:167:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:166:18:166:21 | argv | argv |
|
||||
| argvLocal.c:168:24:168:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:166:18:166:21 | argv | argv |
|
||||
| argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv |
|
||||
| argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv |
|
||||
| argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv |
|
||||
| argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv |
|
||||
| argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv |
|
||||
| argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv |
|
||||
| argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv |
|
||||
| argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv |
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<AssemblyName>Semmle.Extraction.CIL.Driver</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<RootNamespace>Semmle.Extraction.CIL</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<AssemblyName>Semmle.Extraction.CSharp.Driver</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CSharp.Driver</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<RootNamespace>Semmle.Extraction.CSharp</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<RootNamespace>Semmle.Extraction</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<AssemblyName>Semmle.Util</AssemblyName>
|
||||
<RootNamespace>Semmle.Util</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -259,44 +259,47 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable from a source in the given configuration
|
||||
* ignoring call contexts.
|
||||
* taking simple call contexts into consideration.
|
||||
*/
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) {
|
||||
not fullBarrier(node, config) and
|
||||
(
|
||||
config.isSource(node)
|
||||
config.isSource(node) and
|
||||
fromArg = false
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
localFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
additionalLocalFlowStep(mid, node, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
jumpStep(mid, node, config)
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
additionalJumpStep(mid, node, config)
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Node mid |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
storeDirect(mid, _, node) and
|
||||
not outBarrier(mid, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content f |
|
||||
nodeCandFwd1Read(f, node, config) and
|
||||
nodeCandFwd1Read(f, node, fromArg, config) and
|
||||
storeCandFwd1(f, config) and
|
||||
not inBarrier(node, config)
|
||||
)
|
||||
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
|
||||
// flow into a callable
|
||||
exists(Node arg |
|
||||
nodeCandFwd1(arg, config) and
|
||||
viableParamArg(_, node, arg)
|
||||
viableParamArg(_, node, arg) and
|
||||
fromArg = true
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnPosition(pos, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
node = kind.getAnOutNode(call)
|
||||
exists(DataFlowCall call |
|
||||
nodeCandFwd1Out(call, node, false, config) and
|
||||
fromArg = false
|
||||
or
|
||||
nodeCandFwd1OutFromArg(call, node, config) and
|
||||
flowOutCandFwd1(call, fromArg, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnPosition(
|
||||
ReturnPosition pos, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
nodeCandFwd1(ret, config) and
|
||||
nodeCandFwd1(ret, fromArg, config) and
|
||||
getReturnPosition(ret) = pos
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCandFwd1(mid, config) and
|
||||
nodeCandFwd1(mid, fromArg, config) and
|
||||
readDirect(mid, f, node)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +345,7 @@ private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
|
||||
/**
|
||||
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
not fullBarrier(node, config) and
|
||||
@@ -345,71 +355,120 @@ private predicate storeCandFwd1(Content f, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1ReturnKind(
|
||||
DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnPosition pos |
|
||||
nodeCandFwd1ReturnPosition(pos, fromArg, config) and
|
||||
pos = viableReturnPos(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1Out(
|
||||
DataFlowCall call, Node node, boolean fromArg, Configuration config
|
||||
) {
|
||||
exists(ReturnKindExt kind |
|
||||
nodeCandFwd1ReturnKind(call, kind, fromArg, config) and
|
||||
node = kind.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) {
|
||||
nodeCandFwd1Out(call, node, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
nodeCandFwd1(arg, fromArg, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/**
|
||||
* Holds if `node` is part of a path from a source to a sink in the given
|
||||
* configuration ignoring call contexts.
|
||||
* configuration taking simple call contexts into consideration.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) {
|
||||
private predicate nodeCand1(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCand1_0(node, toReturn, config) and
|
||||
nodeCandFwd1(node, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) {
|
||||
nodeCandFwd1(node, config) and
|
||||
config.isSink(node)
|
||||
config.isSink(node) and
|
||||
toReturn = false
|
||||
or
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
exists(Node mid |
|
||||
localFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, _, config) and
|
||||
toReturn = false
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, toReturn, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(DataFlowCall call |
|
||||
nodeCand1Arg(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalLocalFlowStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
jumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
additionalJumpStep(node, mid, config) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(Content f |
|
||||
nodeCand1Store(f, node, config) and
|
||||
readCand1(f, config)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(Node param |
|
||||
viableParamArg(_, param, node) and
|
||||
nodeCand1(param, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos
|
||||
)
|
||||
nodeCand1ArgToReturn(call, node, config) and
|
||||
flowInCand1(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
nodeCand1ReturnPosition(pos, config) and
|
||||
getReturnPosition(node) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, Node out |
|
||||
nodeCand1(out, config) and
|
||||
nodeCand1(out, _, config) and
|
||||
pos = viableReturnPos(call, kind) and
|
||||
out = kind.getAnOutNode(call)
|
||||
)
|
||||
@@ -418,21 +477,21 @@ private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration conf
|
||||
/**
|
||||
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate readCand1(Content f, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
useFieldFlow(config) and
|
||||
nodeCandFwd1(node, unbind(config)) and
|
||||
readDirect(node, f, mid) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
nodeCand1(mid, config)
|
||||
nodeCand1(mid, _, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid |
|
||||
nodeCand1(mid, config) and
|
||||
nodeCand1(mid, toReturn, config) and
|
||||
storeCandFwd1(f, unbind(config)) and
|
||||
storeDirect(node, f, mid)
|
||||
)
|
||||
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
|
||||
*/
|
||||
private predicate readStoreCand1(Content f, Configuration conf) {
|
||||
readCand1(f, conf) and
|
||||
nodeCand1Store(f, _, conf)
|
||||
nodeCand1Store(f, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
nodeCandFwd1(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1Arg(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
nodeCand1(p, toReturn, config) and
|
||||
viableParamArgCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
nodeCand1Arg(call, arg, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an output from `call` is reached in the flow covered by `nodeCand1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) {
|
||||
exists(Node out |
|
||||
nodeCand1(out, toReturn, config) and
|
||||
nodeCandFwd1OutFromArg(call, out, config)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(Node node, Configuration config) {
|
||||
nodeCand1(node, config) and
|
||||
nodeCand1(node, true, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
exists(
|
||||
AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
|
||||
LocalCallContext localCC
|
||||
|
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
@@ -2297,6 +2389,20 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoLocalStep(
|
||||
PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc,
|
||||
AccessPath ap0, Configuration conf
|
||||
) {
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
|
||||
readDirect(node1, f, node2) and
|
||||
|
||||
@@ -266,6 +266,16 @@ module InstructionSanity {
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber {
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
import semmle.code.csharp.ir.internal.Overlap
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
private import ValueNumberingImports
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.implementation.raw.IR
|
||||
private import semmle.code.csharp.Location
|
||||
|
||||
class UnknownLocation = EmptyLocation;
|
||||
|
||||
class UnknownDefaultLocation = EmptyLocation;
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
variableAddressValueNumber(_, irFunc, ast)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
@@ -25,19 +18,18 @@ newtype TValueNumber =
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
@@ -45,6 +37,11 @@ newtype TValueNumber =
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
@@ -61,12 +58,18 @@ newtype TValueNumber =
|
||||
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
|
||||
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
|
||||
*/
|
||||
private class CongruentCopyInstruction extends CopyInstruction {
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this library knows how to assign a value number to the specified instruction, other than
|
||||
* a `unique` value number that is never shared by multiple instructions.
|
||||
@@ -91,20 +94,42 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
or
|
||||
instr instanceof FieldAddressInstruction and
|
||||
count(instr.(FieldAddressInstruction).getField()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = ast and
|
||||
strictcount(instr.getIRVariable().getAST()) = 1
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
@@ -115,6 +140,7 @@ private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
strictcount(instr.getResultIRType()) = 1 and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -133,41 +159,40 @@ private predicate fieldAddressValueNumber(
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
strictcount(instr.getField()) = 1 and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
@@ -182,6 +207,16 @@ private predicate inheritanceConversionValueNumber(
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
|
||||
instr.getResultIRType() = type
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
@@ -189,7 +224,11 @@ private predicate inheritanceConversionValueNumber(
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
or
|
||||
filteredNumberableInstruction(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,6 +244,12 @@ TValueNumber tvalueNumber(Instruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
@@ -213,12 +258,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
@@ -226,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
@@ -241,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -258,14 +303,15 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
|
||||
@@ -834,6 +834,11 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
kind = this.getCaseEdge(caseStmt) and
|
||||
result = getTranslatedStmt(caseStmt).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
not exists(stmt.getDefaultCase()) and
|
||||
tag = SwitchBranchTag() and
|
||||
kind instanceof DefaultEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
private EdgeKind getCaseEdge(CaseStmt caseStmt) {
|
||||
|
||||
@@ -266,6 +266,16 @@ module InstructionSanity {
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,19 +27,19 @@ class ValueNumber extends TValueNumber {
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
else result instanceof Language::UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
import semmle.code.csharp.ir.internal.Overlap
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
private import ValueNumberingImports
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR
|
||||
private import semmle.code.csharp.Location
|
||||
|
||||
class UnknownLocation = EmptyLocation;
|
||||
|
||||
class UnknownDefaultLocation = EmptyLocation;
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
variableAddressValueNumber(_, irFunc, ast)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
@@ -25,19 +18,18 @@ newtype TValueNumber =
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
@@ -106,18 +98,38 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
or
|
||||
instr instanceof FieldAddressInstruction and
|
||||
count(instr.(FieldAddressInstruction).getField()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = ast and
|
||||
strictcount(instr.getIRVariable().getAST()) = 1
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
@@ -128,6 +140,7 @@ private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
strictcount(instr.getResultIRType()) = 1 and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -146,41 +159,40 @@ private predicate fieldAddressValueNumber(
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
strictcount(instr.getField()) = 1 and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
@@ -200,9 +212,9 @@ private predicate loadTotalOverlapValueNumber(
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
|
||||
instr.getResultIRType() = type
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +224,11 @@ private predicate loadTotalOverlapValueNumber(
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
or
|
||||
filteredNumberableInstruction(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,12 +258,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
@@ -255,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
@@ -270,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -287,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
|
||||
@@ -10,6 +10,10 @@ class Function = CSharp::Callable;
|
||||
|
||||
class Location = CSharp::Location;
|
||||
|
||||
class UnknownLocation = CSharp::EmptyLocation;
|
||||
|
||||
class UnknownDefaultLocation = CSharp::EmptyLocation;
|
||||
|
||||
class File = CSharp::File;
|
||||
|
||||
class AST = CSharp::Element;
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
switchInstructionWithoutDefaultEdge
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
<a href="https://help.semmle.com/QL/ql-tools.html" target="_blank">Tools</a>
|
||||
<a href="https://help.semmle.com/QL/ql-explore-queries.html" target="_blank">Queries</a>
|
||||
<a href="https://help.semmle.com/QL/ql-reference-topics.html" target="_blank">Reference</a>
|
||||
<a href="https://blog.semmle.com" target="_blank">Blog</a>
|
||||
<a href="https://help.semmle.com" target="_blank">help.semmle.com</a>
|
||||
</div>
|
||||
<div class="small-bar">
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
Advanced QL
|
||||
===========
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
:hidden:
|
||||
|
||||
./*
|
||||
|
||||
|
||||
Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing.
|
||||
|
||||
- :doc:`Choosing appropriate ways to constrain types <constraining-types>`
|
||||
- :doc:`Determining the most specific types of a variable <determining-specific-types-variables>`
|
||||
- :doc:`Monotonic aggregates in QL <monotonic-aggregates>`
|
||||
@@ -1,73 +0,0 @@
|
||||
Constraining types
|
||||
==================
|
||||
|
||||
Type constraint methods
|
||||
-----------------------
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
The examples below use the CodeQL library for Java. All libraries support using these methods to constrain variables, the only difference is in the names of the classes used.
|
||||
|
||||
There are several ways of imposing type constraints on variables:
|
||||
|
||||
- Use an ``instanceof`` test, for example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from Type t
|
||||
where t instanceof Class
|
||||
select t
|
||||
|
||||
- Use a cast, for example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from Type t
|
||||
where t.(Class).getASupertype().hasName("List")
|
||||
select t
|
||||
|
||||
- Set the variable equal to another variable with the required type using exists, for example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from Type t
|
||||
where exists(Class c |
|
||||
c = t
|
||||
and c.getASupertype().hasName("List")
|
||||
)
|
||||
select t
|
||||
|
||||
- Pass the variable to a predicate that expects a variable of the required type, for example:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
predicate derivedFromList(Class c) {
|
||||
c.getASupertype().hasName("List")
|
||||
}
|
||||
|
||||
from Type t
|
||||
where derivedFromList(t)
|
||||
select t
|
||||
|
||||
All of these methods constrain the variable ``t`` to have values of type ``Class``.
|
||||
|
||||
Choosing between the methods
|
||||
----------------------------
|
||||
|
||||
These methods have advantages and disadvantages depending on the extent to which you need to work with the variable as the new type:
|
||||
|
||||
- ``instanceof`` only checks that the variable has the required type.
|
||||
- A cast gives you one, and only one, access to the variable as the new type.
|
||||
- Creating a new variable with ``exists`` or a predicate parameter allows repeated access to the variable as the new type.
|
||||
|
||||
- Note that due to the ability to overload predicates in a class, predicates that belong to a class must be supplied with arguments of the exact type they specify, and so this technique will not work in that situation.
|
||||
@@ -1,28 +0,0 @@
|
||||
Determining the most specific types of a variable
|
||||
=================================================
|
||||
|
||||
It is sometimes useful to be able to determine what types an entity has -- especially when you are unfamiliar with the library used by a query. To help with this, there is a predicate called ``getAQlClass()``, which returns the most specific QL types of the entity that it is called on.
|
||||
|
||||
This can be useful when you are not sure of the most precise class of a value. Discovering a more precise class can allow you to cast to it and use predicates that are not available on the more general class.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
If you were working with a Java database, you might use ``getAQlClass()`` on every ``Expr`` in a callable called ``c``:
|
||||
|
||||
**Java example**
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from Expr e, Callable c
|
||||
where
|
||||
c.getDeclaringType().hasQualifiedName("my.namespace.name", "MyClass")
|
||||
and c.getName() = "c"
|
||||
and e.getEnclosingCallable() = c
|
||||
select e, e.getAQlClass()
|
||||
|
||||
The result of this query is a list of the most specific types of every ``Expr`` in that function. You will see multiple results for some expressions because that expression is represented by more than one type.
|
||||
|
||||
For example, ``StringLiteral``\ s like ``"Hello"`` in Java belong to both the ``StringLiteral`` class (a specialization of the ``Literal`` class) and the ``CompileTimeConstantExpr`` class. So any instances of ``StringLiteral``\ s in the results will produce more than one result, one for each of the classes to which they belong.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user