Merge remote-tracking branch 'upstream/master' into UselessCat

This commit is contained in:
Erik Krogh Kristensen
2020-02-28 09:56:23 +01:00
468 changed files with 12761 additions and 4082 deletions

View File

@@ -46,6 +46,12 @@ Follow the steps below to help other users understand what your query does, and
Query help files explain the purpose of your query to other users. Write your query help in a `.qhelp` file and save it in the same directory as your new query. Query help files explain the purpose of your query to other users. Write your query help in a `.qhelp` file and save it in the same directory as your new query.
For more information on writing query help, see the [Query help style guide](https://github.com/Semmle/ql/blob/master/docs/query-help-style-guide.md). For more information on writing query help, see the [Query help style guide](https://github.com/Semmle/ql/blob/master/docs/query-help-style-guide.md).
7. **Maintain backwards compatibility**
The standard CodeQL libraries must evolve in a backwards compatible manner. If any backwards incompatible changes need to be made, the existing API must first be marked as deprecated. This is done by adding a `deprecated` annotation along with a QLDoc reference to the replacement API. Only after at least one full release cycle has elapsed may the old API be removed.
In addition to contributions to our standard queries and libraries, we also welcome contributions of a more experimental nature, which do not need to fulfill all the requirements listed above. See the guidelines for [experimental queries and libraries](docs/experimental.md) for details.
## Using your personal data ## Using your personal data
If you contribute to this project, we will record your name and email If you contribute to this project, we will record your name and email

View File

@@ -46,3 +46,5 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
the following improvements: the following improvements:
* The library now models data flow through `strdup` and similar functions. * The library now models data flow through `strdup` and similar functions.
* The library now models data flow through formatting functions such as `sprintf`. * 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 ## General improvements
* TypeScript 3.8 is now supported.
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). * 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, * 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 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: * Support for the following frameworks and libraries has been improved:
- [Electron](https://electronjs.org/) - [Electron](https://electronjs.org/)
- [Handlebars](https://www.npmjs.com/package/handlebars) - [Handlebars](https://www.npmjs.com/package/handlebars)
@@ -37,6 +43,7 @@
| Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. | | Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. |
| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. | | Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. |
| Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. | | Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. |
| Polynomial regular expression used on uncontrolled data (`js/polynomial-redos`) | security, external/cwe/cwe-730, external/cwe/cwe-400 | Highlights expensive regular expressions that may be used on malicious input. Results are shown on LGTM by default. |
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive copying operations that are susceptible to prototype pollution. Results are shown on LGTM by default. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive copying operations that are susceptible to prototype pollution. Results are shown on LGTM by default. |
| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. | | Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. |
| Useless use of cat (`js/useless-use-of-cat`) | correctness, security, maintainability | Highlights command executions of `cat` where the fs API should be used instead. Results are shown on LGTM by default. | | Useless use of cat (`js/useless-use-of-cat`) | correctness, security, maintainability | Highlights command executions of `cat` where the fs API should be used instead. Results are shown on LGTM by default. |

View File

@@ -222,10 +222,12 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", "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" "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/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/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": [ "C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",

View File

@@ -0,0 +1 @@
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

@@ -1,7 +1,5 @@
private import cpp private import cpp
Function viableImpl(Call call) { result = viableCallable(call) }
/** /**
* Gets a function that might be called by `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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and readDirect(node1, f, node2) and

View File

@@ -132,16 +132,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/ */
predicate jumpStep(Node n1, Node n2) { none() } 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 = private newtype TContent =
TFieldContent(Field f) or TFieldContent(Field f) or
TCollectionContent() or TCollectionContent() or

View File

@@ -343,6 +343,7 @@ private Element adjustedSink(DataFlow::Node sink) {
result.(AssignOperation).getAnOperand() = sink.asExpr() result.(AssignOperation).getAnOperand() = sink.asExpr()
} }
cached
predicate tainted(Expr source, Element tainted) { predicate tainted(Expr source, Element tainted) {
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink | exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
cfg.hasFlow(getNodeForSource(source), sink) and cfg.hasFlow(getNodeForSource(source), sink) and
@@ -350,6 +351,7 @@ predicate tainted(Expr source, Element tainted) {
) )
} }
cached
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) { predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
tainted(source, tainted) and tainted(source, tainted) and
globalVar = "" 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.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate 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`. * 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and readDirect(node1, f, node2) and

View File

@@ -67,16 +67,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/ */
predicate jumpStep(Node n1, Node n2) { none() } 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 = private newtype TContent =
TFieldContent(Field f) or TFieldContent(Field f) or
TCollectionContent() or TCollectionContent() or

View File

@@ -303,10 +303,12 @@ ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
VariableNode variableNode(Variable v) { result.getVariable() = v } VariableNode variableNode(Variable v) { result.getVariable() = v }
/** /**
* DEPRECATED: See UninitializedNode.
*
* Gets the `Node` corresponding to the value of an uninitialized local * Gets the `Node` corresponding to the value of an uninitialized local
* variable `v`. * variable `v`.
*/ */
UninitializedNode uninitializedNode(LocalVariable v) { result.getLocalVariable() = v } Node uninitializedNode(LocalVariable v) { none() }
/** /**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local

View File

@@ -266,6 +266,16 @@ module InstructionSanity {
funcText = Language::getIdentityString(func.getFunction()) 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() { final Language::Location getLocation() {
if if
exists(Instruction i | exists(Instruction i |
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
) )
then then
result = result =
min(Language::Location l | min(Language::Location l |
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
| |
l l
order by order by
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn() 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.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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 ValueNumberingImports
private import cpp
newtype TValueNumber = newtype TValueNumber =
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
@@ -15,7 +14,7 @@ newtype TValueNumber =
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
@@ -33,7 +32,8 @@ newtype TValueNumber =
unaryValueNumber(_, irFunc, opcode, operand) unaryValueNumber(_, irFunc, opcode, operand)
} or } or
TInheritanceConversionValueNumber( 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) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
instr.getEnclosingIRFunction() = irFunc instr.getEnclosingIRFunction() = irFunc
} }
predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, IRType type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and

View File

@@ -266,6 +266,16 @@ module InstructionSanity {
funcText = Language::getIdentityString(func.getFunction()) 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() { final Language::Location getLocation() {
if if
exists(Instruction i | exists(Instruction i |
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
) )
then then
result = result =
min(Language::Location l | min(Language::Location l |
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
| |
l l
order by order by
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn() 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.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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 ValueNumberingImports
private import cpp
newtype TValueNumber = newtype TValueNumber =
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
@@ -15,7 +14,7 @@ newtype TValueNumber =
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
@@ -33,7 +32,8 @@ newtype TValueNumber =
unaryValueNumber(_, irFunc, opcode, operand) unaryValueNumber(_, irFunc, opcode, operand)
} or } or
TInheritanceConversionValueNumber( 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) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
instr.getEnclosingIRFunction() = irFunc instr.getEnclosingIRFunction() = irFunc
} }
predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, IRType type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and

View File

@@ -102,6 +102,19 @@ private module Cached {
result = getMemoryOperandDefinition(instr, _, _) 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 * 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. * through a phi instruction and therefore should be impossible.
@@ -115,7 +128,7 @@ private module Cached {
cached cached
predicate isInCycle(Instruction instr) { predicate isInCycle(Instruction instr) {
instr instanceof Instruction and instr instanceof Instruction and
getNonPhiOperandDef+(instr) = instr getNonPhiOperandDefOfIntermediate+(instr) = instr
} }
cached cached

View File

@@ -655,6 +655,11 @@ class TranslatedSwitchStmt extends TranslatedStmt {
kind = getCaseEdge(switchCase) and kind = getCaseEdge(switchCase) and
result = getTranslatedStmt(switchCase).getFirstInstruction() 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) { override Instruction getChildSuccessor(TranslatedElement child) {

View File

@@ -266,6 +266,16 @@ module InstructionSanity {
funcText = Language::getIdentityString(func.getFunction()) 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() { final Language::Location getLocation() {
if if
exists(Instruction i | exists(Instruction i |
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
) )
then then
result = result =
min(Language::Location l | min(Language::Location l |
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
| |
l l
order by order by
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn() 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.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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 ValueNumberingImports
private import cpp
newtype TValueNumber = newtype TValueNumber =
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) { TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
@@ -15,7 +14,7 @@ newtype TValueNumber =
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, TValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
@@ -33,7 +32,8 @@ newtype TValueNumber =
unaryValueNumber(_, irFunc, opcode, operand) unaryValueNumber(_, irFunc, opcode, operand)
} or } or
TInheritanceConversionValueNumber( 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) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -136,7 +136,7 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
instr.getEnclosingIRFunction() = irFunc instr.getEnclosingIRFunction() = irFunc
} }
predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, IRType type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and

View File

@@ -13,6 +13,10 @@ class Function = Cpp::Function;
class Location = Cpp::Location; class Location = Cpp::Location;
class UnknownLocation = Cpp::UnknownLocation;
class UnknownDefaultLocation = Cpp::UnknownDefaultLocation;
class File = Cpp::File; class File = Cpp::File;
class AST = Cpp::Locatable; 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 parameterIsAlwaysReturned(int i) { none() }
override predicate hasOnlySpecificReadSideEffects() { none() } override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { 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. * 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 * 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(); abstract predicate hasOnlySpecificReadSideEffects();
/** /**
* Holds if the function never writes to memory that remains allocated after the function * 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 * 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(); abstract predicate hasOnlySpecificWriteSideEffects();
@@ -43,7 +47,6 @@ abstract class SideEffectFunction extends Function {
*/ */
predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } 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 * Gets the index of the parameter that indicates the size of the buffer pointed to by the
* parameter at index `i`. * parameter at index `i`.

View File

@@ -2,4 +2,4 @@
* Support for tracking tainted data through the program. * Support for tracking tainted data through the program.
*/ */
import TaintTrackingImpl import semmle.code.cpp.ir.dataflow.DefaultTaintTracking

View File

@@ -1 +1 @@
import GlobalValueNumberingImpl import semmle.code.cpp.ir.internal.ASTValueNumbering

View File

@@ -0,0 +1 @@
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

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 from Expr source, Element tainted, string globalVar
where where

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.security.TaintTracking as AST import semmle.code.cpp.security.TaintTrackingImpl as AST
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IR import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IR
import cpp import cpp

View File

@@ -8070,6 +8070,239 @@ ir.cpp:
# 1170| Type = [ArrayType] const char[4] # 1170| Type = [ArrayType] const char[4]
# 1170| Value = [StringLiteral] "foo" # 1170| Value = [StringLiteral] "foo"
# 1170| ValueCategory = lvalue # 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: perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| params: # 4| params:

View File

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

View File

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

View File

@@ -1170,4 +1170,53 @@ String ReturnObjectImpl() {
return String("foo"); 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 // semmle-extractor-options: -std=c++17 --clang

View File

@@ -6052,6 +6052,182 @@ ir.cpp:
# 1169| v1169_8(void) = AliasedUse : ~mu1169_4 # 1169| v1169_8(void) = AliasedUse : ~mu1169_4
# 1169| v1169_9(void) = ExitFunction : # 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: perf-regression.cpp:
# 6| void Big::Big() # 6| void Big::Big()
# 6| Block 0 # 6| Block 0

View File

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

View File

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

View File

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

View File

@@ -886,27 +886,25 @@ ssa.cpp:
# 199| r199_7(char *) = Load : &:r199_6, m198_11 # 199| r199_7(char *) = Load : &:r199_6, m198_11
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 # 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 # 199| m199_12(int) = Store : &:r199_1, r199_9
# 199| m199_13(int) = Store : &:r199_1, r199_9
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] : # 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_7 # 200| r200_3(char *) = Load : &:r200_2, m198_7
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 # 200| r200_7(glval<int>) = VariableAddress[ret] :
# 200| r200_8(glval<int>) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12
# 200| r200_9(int) = Load : &:r200_8, m199_13 # 200| r200_9(int) = Add : r200_8, r200_5
# 200| r200_10(int) = Add : r200_9, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9
# 200| m200_11(int) = Store : &:r200_8, r200_10
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] : # 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_3(int) = Load : &:r201_2, m198_15
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 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_7(char *) = Load : &:r199_6, m198_11
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_4 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 # 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 # 199| m199_12(int) = Store : &:r199_1, r199_9
# 199| m199_13(int) = Store : &:r199_1, r199_9
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] : # 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_7 # 200| r200_3(char *) = Load : &:r200_2, m198_7
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 # 200| r200_7(glval<int>) = VariableAddress[ret] :
# 200| r200_8(glval<int>) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12
# 200| r200_9(int) = Load : &:r200_8, m199_13 # 200| r200_9(int) = Add : r200_8, r200_5
# 200| r200_10(int) = Add : r200_9, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9
# 200| m200_11(int) = Store : &:r200_8, r200_10
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] : # 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_3(int) = Load : &:r201_2, m198_15
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

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

View File

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

View File

@@ -829,27 +829,25 @@ ssa.cpp:
# 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_7(char *) = Load : &:r199_6, m198_10
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 # 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 # 199| m199_12(int) = Store : &:r199_1, r199_9
# 199| m199_13(int) = Store : &:r199_1, r199_9
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] : # 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_3(char *) = Load : &:r200_2, m198_6
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 # 200| r200_7(glval<int>) = VariableAddress[ret] :
# 200| r200_8(glval<int>) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12
# 200| r200_9(int) = Load : &:r200_8, m199_13 # 200| r200_9(int) = Add : r200_8, r200_5
# 200| r200_10(int) = Add : r200_9, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9
# 200| m200_11(int) = Store : &:r200_8, r200_10
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] : # 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_3(int) = Load : &:r201_2, m198_14
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 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_7(char *) = Load : &:r199_6, m198_10
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_4 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 # 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 # 199| m199_12(int) = Store : &:r199_1, r199_9
# 199| m199_13(int) = Store : &:r199_1, r199_9
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] : # 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_3(char *) = Load : &:r200_2, m198_6
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 # 200| r200_7(glval<int>) = VariableAddress[ret] :
# 200| r200_8(glval<int>) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12
# 200| r200_9(int) = Load : &:r200_8, m199_13 # 200| r200_9(int) = Add : r200_8, r200_5
# 200| r200_10(int) = Add : r200_9, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9
# 200| m200_11(int) = Store : &:r200_8, r200_10
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] : # 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_3(int) = Load : &:r201_2, m198_14
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

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

View File

@@ -15,6 +15,7 @@ containsLoopOfForwardEdges
lostReachability lostReachability
backEdgeCountMismatch backEdgeCountMismatch
useNotDominatedByDefinition useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType 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 | | range_analysis.c:371:37:371:39 | Constant: 500 |
backEdgeCountMismatch backEdgeCountMismatch
useNotDominatedByDefinition useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge
missingCanonicalLanguageType missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType 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() | | 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) | | 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**) | | 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 missingCanonicalLanguageType
multipleCanonicalLanguageTypes multipleCanonicalLanguageTypes
missingIRType missingIRType

View File

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

View File

@@ -1,5 +1,5 @@
import cpp import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
from GVN g from GVN g
where strictcount(g.getAnExpr()) > 1 where strictcount(g.getAnExpr()) > 1

View File

@@ -1,5 +1,5 @@
import cpp import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
// Every expression should have exactly one GVN. // Every expression should have exactly one GVN.
// So this query should have zero results. // So this query should have zero results.

View File

@@ -1,5 +1,5 @@
import cpp 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.internal.ASTValueNumbering as IR
import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.IR

View File

@@ -12,6 +12,5 @@
| test.cpp:46:2:46:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. | | test.cpp:46:2:46:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
| test.cpp:47:2:47:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. | | test.cpp:47:2:47:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
| test.cpp:60:3:60:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. | | test.cpp:60:3:60:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| test.cpp:63:3:63:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. | | test.cpp:68:2:68:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| test.cpp:79:3:79:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. | | test.cpp:79:3:79:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| test.cpp:82:3:82:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |

View File

@@ -1,5 +1,10 @@
| tests.c:28:3:28:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | | tests.c:28:3:28:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
| tests.c:29:3:29:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | | tests.c:29:3:29:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 | | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 |
| tests.c:34:25:34:33 | buffer100 | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv | | tests.c:34:25:34:33 | buffer100 | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv |

View File

@@ -1,4 +1,3 @@
| test1.c:18:16:18:16 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value | | test1.c:18:16:18:16 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:33:11:33:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value | | test1.c:33:11:33:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:37:11:37:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:53:15:53:15 | j | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value | | test1.c:53:15:53:15 | j | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |

View File

@@ -146,19 +146,21 @@ int main(int argc, char **argv) {
// BAD: i8 value comes from argv // BAD: i8 value comes from argv
char *i8; char *i8;
*(&i8 + 1) = argv[1]; *(&i8) = argv[1];
printf(i8); printf(i8);
printWrapper(i8); printWrapper(i8);
// BAD: i9 value comes from argv // BAD: i9 value comes from argv
char *i9; char i9buf[32];
memcpy(1 ? i9++ : 0, argv[1], 1); char *i9 = i9buf;
memcpy(1 ? ++i9 : 0, argv[1], 1);
printf(i9); printf(i9);
printWrapper(i9); printWrapper(i9);
// BAD: i91 value comes from argv // BAD: i91 value comes from argv
char *i91; char i91buf[64];
memcpy(0 ? 0 : (char *)((int) i91 * 2), argv[1], 1); char *i91 = &i91buf[0];
memcpy(0 ? 0 : i91, argv[1] + 1, 1);
printf(i91); printf(i91);
printWrapper(i91); printWrapper(i91);

View File

@@ -16,15 +16,13 @@
| argvLocal.c:132:15:132:20 | ... + ... | 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:126:10:126:13 | argv | argv | | argvLocal.c:132:15:132:20 | ... + ... | 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:126:10:126:13 | argv | argv |
| argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| 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: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:139:9:139:26 | ... ? ... : ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:140:15:140:32 | ... ? ... : ... | 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:126:10:126:13 | 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: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: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: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:15:149:18 | 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:15:149:18 | 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:156:9:156:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:155:23:155:26 | 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:157:15:157: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:155:23:155: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:162:9:162:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:161:42:161:45 | 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:163:15:163: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:161:42:161:45 | 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: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: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: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: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

@@ -3,6 +3,3 @@
| funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets | | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets |
| funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets | | funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets |
| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets | | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets |
| funcsLocal.c:47:9:47:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:46:7:46:9 | * ... | gets |
| funcsLocal.c:53:9:53:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:52:8:52:11 | call to gets | gets |
| funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread |

View File

@@ -1,3 +1,4 @@
| ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:61:8:61:11 | argv | argv |
| ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv | | ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv |
| ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv | | ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv |
| ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv | | ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv |

View File

@@ -1,6 +1,8 @@
| test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:43:31:43:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:45:31:45:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:52:21:52:27 | call to realloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
| test.cpp:55:11:55:24 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |

View File

@@ -1,7 +1,6 @@
| test.c:17:10:17:12 | min | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:8:9:8:15 | 2147483647 | Extreme value | | test.c:17:10:17:12 | min | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:8:9:8:15 | 2147483647 | Extreme value |
| test.c:48:3:48:5 | sc2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:47:9:47:16 | - ... | Extreme value | | test.c:48:3:48:5 | sc2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:47:9:47:16 | - ... | Extreme value |
| test.c:50:3:50:5 | sc3 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:49:9:49:16 | 127 | Extreme value | | test.c:50:3:50:5 | sc3 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:49:9:49:16 | 127 | Extreme value |
| test.c:56:3:56:5 | sc5 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:9:54:16 | 127 | Extreme value |
| test.c:59:3:59:5 | sc6 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:58:9:58:16 | 127 | Extreme value | | test.c:59:3:59:5 | sc6 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:58:9:58:16 | 127 | Extreme value |
| test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value | | test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value |
| test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | | test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |

View File

@@ -8,4 +8,3 @@
| test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value | | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value |
| test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value | | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value |
| test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value | | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
| test.cpp:37:7:37:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | Uncontrolled value |

View File

@@ -1 +1,2 @@
| test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... |
| test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... |

View File

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

View File

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

View File

@@ -6,6 +6,7 @@
<AssemblyName>Semmle.Extraction.CIL.Driver</AssemblyName> <AssemblyName>Semmle.Extraction.CIL.Driver</AssemblyName>
<RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace> <RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -6,6 +6,7 @@
<RootNamespace>Semmle.Extraction.CIL</RootNamespace> <RootNamespace>Semmle.Extraction.CIL</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -6,6 +6,7 @@
<AssemblyName>Semmle.Extraction.CSharp.Driver</AssemblyName> <AssemblyName>Semmle.Extraction.CSharp.Driver</AssemblyName>
<RootNamespace>Semmle.Extraction.CSharp.Driver</RootNamespace> <RootNamespace>Semmle.Extraction.CSharp.Driver</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

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

View File

@@ -6,6 +6,7 @@
<RootNamespace>Semmle.Extraction.CSharp</RootNamespace> <RootNamespace>Semmle.Extraction.CSharp</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

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

View File

@@ -6,6 +6,7 @@
<RootNamespace>Semmle.Extraction</RootNamespace> <RootNamespace>Semmle.Extraction</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

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

View File

@@ -5,6 +5,7 @@
<AssemblyName>Semmle.Util</AssemblyName> <AssemblyName>Semmle.Util</AssemblyName>
<RootNamespace>Semmle.Util</RootNamespace> <RootNamespace>Semmle.Util</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1 @@
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and 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 * 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 not fullBarrier(node, config) and
( (
config.isSource(node) config.isSource(node) and
fromArg = false
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
localFlowStep(mid, node, config) localFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
additionalLocalFlowStep(mid, node, config) additionalLocalFlowStep(mid, node, config)
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
jumpStep(mid, node, config) jumpStep(mid, node, config) and
fromArg = false
) )
or or
exists(Node mid | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, config) and
additionalJumpStep(mid, node, config) additionalJumpStep(mid, node, config) and
fromArg = false
) )
or or
// store // store
exists(Node mid | exists(Node mid |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
storeDirect(mid, _, node) and storeDirect(mid, _, node) and
not outBarrier(mid, config) not outBarrier(mid, config)
) )
or or
// read // read
exists(Content f | exists(Content f |
nodeCandFwd1Read(f, node, config) and nodeCandFwd1Read(f, node, fromArg, config) and
storeCandFwd1(f, config) and storeCandFwd1(f, config) and
not inBarrier(node, config) not inBarrier(node, config)
) )
@@ -304,30 +307,37 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
// flow into a callable // flow into a callable
exists(Node arg | exists(Node arg |
nodeCandFwd1(arg, config) and nodeCandFwd1(arg, config) and
viableParamArg(_, node, arg) viableParamArg(_, node, arg) and
fromArg = true
) )
or or
// flow out of a callable // flow out of a callable
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind | exists(DataFlowCall call |
nodeCandFwd1ReturnPosition(pos, config) and nodeCandFwd1Out(call, node, false, config) and
pos = viableReturnPos(call, kind) and fromArg = false
node = kind.getAnOutNode(call) or
nodeCandFwd1OutFromArg(call, node, config) and
flowOutCandFwd1(call, fromArg, config)
) )
) )
} }
pragma[noinline] private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
pragma[nomagic]
private predicate nodeCandFwd1ReturnPosition(
ReturnPosition pos, boolean fromArg, Configuration config
) {
exists(ReturnNodeExt ret | exists(ReturnNodeExt ret |
nodeCandFwd1(ret, config) and nodeCandFwd1(ret, fromArg, config) and
getReturnPosition(ret) = pos getReturnPosition(ret) = pos
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCandFwd1(mid, config) and nodeCandFwd1(mid, fromArg, config) and
readDirect(mid, f, node) 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`. * 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) { private predicate storeCandFwd1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
not fullBarrier(node, config) and 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] bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() } 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 * 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] 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 nodeCandFwd1(node, config) and
config.isSink(node) config.isSink(node) and
toReturn = false
or or
nodeCandFwd1(node, unbind(config)) and exists(Node mid |
( localFlowStep(node, mid, config) and
exists(Node mid | nodeCand1(mid, toReturn, config)
localFlowStep(node, mid, config) and )
nodeCand1(mid, 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 or
exists(Node mid | nodeCand1ArgToReturn(call, node, config) and
additionalLocalFlowStep(node, mid, config) and flowInCand1(call, toReturn, config)
nodeCand1(mid, config) )
) or
or // flow out of a callable
exists(Node mid | exists(ReturnPosition pos |
jumpStep(node, mid, config) and nodeCand1ReturnPosition(pos, config) and
nodeCand1(mid, config) getReturnPosition(node) = pos and
) toReturn = true
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
)
) )
} }
pragma[noinline] pragma[nomagic]
private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) }
pragma[nomagic]
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, ReturnKindExt kind, Node out | exists(DataFlowCall call, ReturnKindExt kind, Node out |
nodeCand1(out, config) and nodeCand1(out, _, config) and
pos = viableReturnPos(call, kind) and pos = viableReturnPos(call, kind) and
out = kind.getAnOutNode(call) 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`. * 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) { private predicate readCand1(Content f, Configuration config) {
exists(Node mid, Node node | exists(Node mid, Node node |
useFieldFlow(config) and useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and nodeCandFwd1(node, unbind(config)) and
readDirect(node, f, mid) and readDirect(node, f, mid) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
nodeCand1(mid, config) nodeCand1(mid, _, config)
) )
} }
pragma[nomagic] 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 | exists(Node mid |
nodeCand1(mid, config) and nodeCand1(mid, toReturn, config) and
storeCandFwd1(f, unbind(config)) and storeCandFwd1(f, unbind(config)) and
storeDirect(node, f, mid) storeDirect(node, f, mid)
) )
@@ -444,11 +503,45 @@ private predicate nodeCand1Store(Content f, Node node, Configuration config) {
*/ */
private predicate readStoreCand1(Content f, Configuration conf) { private predicate readStoreCand1(Content f, Configuration conf) {
readCand1(f, conf) and 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) { private predicate throughFlowNodeCand(Node node, Configuration config) {
nodeCand1(node, config) and nodeCand1(node, true, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not inBarrier(node, config) and not inBarrier(node, config) and
not outBarrier(node, config) not outBarrier(node, config)
@@ -2257,13 +2350,12 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) {
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf | exists(
midnode = mid.getNode() and AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing,
conf = mid.getConfiguration() and LocalCallContext localCC
cc = mid.getCallContext() and |
sc = mid.getSummaryCtx() and pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and localCC = getLocalCallContext(cc, enclosing)
ap0 = mid.getAp()
| |
localFlowBigStep(midnode, node, true, conf, localCC) and localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0 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() 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] pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) { private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
readDirect(node1, f, node2) and readDirect(node1, f, node2) and

View File

@@ -266,6 +266,16 @@ module InstructionSanity {
funcText = Language::getIdentityString(func.getFunction()) 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() { final Language::Location getLocation() {
if if
exists(Instruction i | exists(Instruction i |
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation i = getAnInstruction() and not i.getLocation() instanceof Language::UnknownLocation
) )
then then
result = result =
min(Language::Location l | min(Language::Location l |
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation l = getAnInstruction().getLocation() and not l instanceof Language::UnknownLocation
| |
l l
order by order by
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn() 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.Overlap
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR

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