Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams

This commit is contained in:
Robert Marsh
2020-02-26 13:15:27 -08:00
234 changed files with 10496 additions and 2737 deletions

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,5 @@
private import cpp
Function viableImpl(Call call) { result = viableCallable(call) }
/**
* Gets a function that might be called by `call`.
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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`.
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.security.TaintTracking
import semmle.code.cpp.security.TaintTrackingImpl
from Expr source, Element tainted, string globalVar
where

View File

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

View File

@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View 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()
)
}

View 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);
}
}

View File

@@ -568,6 +568,7 @@ lostReachability
| range_analysis.c:371:37:371:39 | Constant: 500 |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

@@ -577,6 +577,7 @@ lostReachability
| range_analysis.c:371:37:371:39 | Constant: 500 |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>

View File

@@ -8,6 +8,7 @@
<OutputType>Exe</OutputType>
<StartupObject />
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>

View File

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

View File

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

View File

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

View File

@@ -9,6 +9,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>

View File

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

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>

View File

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

View File

@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

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

View File

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

View File

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

View File

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