Merge branch 'master' into testmerge

This commit is contained in:
Rebecca Valentine
2020-03-17 12:32:45 -07:00
308 changed files with 18421 additions and 11175 deletions

View File

@@ -1,62 +1,65 @@
# Contributing to CodeQL
We welcome contributions to our standard library and standard checks. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request!
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request!
Before we accept your pull request, we require that you have agreed to our Contributor License Agreement, this is not something that you need to do before you submit your pull request, but until you've done so, we will be unable to accept your contribution.
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
## Adding a new query
If you have an idea for a query that you would like to share with other Semmle users, please open a pull request to add it to this repository.
Follow the steps below to help other users understand what your query does, and to ensure that your query is consistent with the other Semmle queries.
## Submitting a new experimental query
1. **Consult the documentation for query writers**
If you have an idea for a query that you would like to share with other CodeQL users, please open a pull request to add it to this repository. New queries start out in a `<language>/ql/src/experimental` directory, to which they can be merged when they meet the following requirements.
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
1. **Directory structure**
2. **Format your code correctly**
There are five language-specific query directories in this repository:
All of Semmle's standard queries and libraries are uniformly formatted for clarity and consistency, so we strongly recommend that all contributions follow the same formatting guidelines. If you use CodeQL for VS Code, you can autoformat your query in the [Editor](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting). For more information, see the [CodeQL style guide](https://github.com/Semmle/ql/blob/master/docs/ql-style-guide.md).
* C/C++: `cpp/ql/src`
* C#: `csharp/ql/src`
* Java: `java/ql/src`
* JavaScript: `javascript/ql/src`
* Python: `python/ql/src`
3. **Make sure your query has the correct metadata**
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/Semmle/ql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.
- The structure of an `experimental` subdirectory mirrors the structure of its parent directory.
- Select or create an appropriate directory in `experimental` based on the existing directory structure of `experimental` or its parent directory.
Query metadata is used by Semmle's analysis to identify your query and make sure the query results are displayed properly.
The most important metadata to include are the `@name`, `@description`, and the `@kind`.
Other metadata properties (`@precision`, `@severity`, and `@tags`) are usually added after the query has been reviewed by Semmle staff.
For more information on writing query metadata, see the [Query metadata style guide](https://github.com/Semmle/ql/blob/master/docs/query-metadata-style-guide.md).
2. **Query metadata**
4. **Make sure the `select` statement is compatible with the query type**
- The query `@id` must conform to all the requirements in the [guide on query metadata](docs/query-metadata-style-guide.md#query-id-id). In particular, it must not clash with any other queries in the repository, and it must start with the appropriate language-specific prefix.
- The query must have a `@name` and `@description` to explain its purpose.
- The query must have a `@kind` and `@problem.severity` as required by CodeQL tools.
The `select` statement of your query must be compatible with the query type (determined by the `@kind` metadata property) for alert or path results to be displayed correctly in LGTM and CodeQL for VS Code.
For more information on `select` statement format, see [Introduction to query files](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
For details, see the [guide on query metadata](docs/query-metadata-style-guide.md).
5. **Save your query in a `.ql` file in the correct language directory in this repository**
Make sure the `select` statement is compatible with the query `@kind`. See [Introduction to query files](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
There are five language-specific directories in this repository:
* C/C++: `ql/cpp/ql/src`
* C#: `ql/csharp/ql/src`
* Java: `ql/java/ql/src`
* JavaScript: `ql/javascript/ql/src`
* Python: `ql/python/ql/src`
3. **Formatting**
Each language-specific directory contains further subdirectories that group queries based on their `@tags` properties or purpose. Select the appropriate subdirectory for your new query, or create a new one if necessary.
- The queries and libraries must be [autoformatted](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting).
6. **Write a query help file**
4. **Compilation**
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).
- Compilation of the query and any associated libraries and tests must be resilient to future development of the [supported](docs/supported-queries.md) libraries. This means that the functionality cannot use internal libraries, cannot depend on the output of `getAQlClass`, and cannot make use of regexp matching on `toString`.
- The query and any associated libraries and tests must not cause any compiler warnings to be emitted (such as use of deprecated functionality or missing `override` annotations).
7. **Maintain backwards compatibility**
5. **Results**
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.
- The query must have at least one true positive result on some revision of a real project.
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.
6. **Contributor License Agreement**
- The contributor can satisfy the [CLA](#contributor-license-agreement).
Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings.
After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md).
## Using your personal data
If you contribute to this project, we will record your name and email
address (as provided by you with your contributions) as part of the code
repositories, which might be made public. We might also use this information
repositories, which are public. We might also use this information
to contact you in relation to your contributions, as well as in the
normal course of software development. We also store records of your
CLA agreements. Under GDPR legislation, we do this

View File

@@ -1,6 +1,6 @@
# CodeQL
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com), and the other products that [Semmle](https://semmle.com) makes available to its customers worldwide.
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide.
## How do I learn CodeQL and run queries?
@@ -13,4 +13,4 @@ We welcome contributions to our standard library and standard checks. Do you hav
## License
The code in this repository is licensed under [Apache License 2.0](LICENSE) by [Semmle](https://semmle.com).
The code in this repository is licensed under [Apache License 2.0](LICENSE) by [GitHub](https://github.com).

View File

@@ -18,12 +18,14 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
| Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Fixed false positive results in template code. |
| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. |
| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. |
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |
| Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. |
| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. |
## Changes to libraries

View File

@@ -19,9 +19,13 @@
- 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 flow summaries has been more clearly marked as being experimental and moved to the new `experimental` folder.
* Support for the following frameworks and libraries has been improved:
- [Electron](https://electronjs.org/)
- [fstream](https://www.npmjs.com/package/fstream)
- [Handlebars](https://www.npmjs.com/package/handlebars)
- [jsonfile](https://www.npmjs.com/package/jsonfile)
- [Koa](https://www.npmjs.com/package/koa)
- [Node.js](https://nodejs.org/)
- [Socket.IO](https://socket.io/)
@@ -30,10 +34,20 @@
- [for-in](https://www.npmjs.com/package/for-in)
- [for-own](https://www.npmjs.com/package/for-own)
- [http2](https://nodejs.org/api/http2.html)
- [jQuery](https://jquery.com/)
- [lazy-cache](https://www.npmjs.com/package/lazy-cache)
- [mongodb](https://www.npmjs.com/package/mongodb)
- [ncp](https://www.npmjs.com/package/ncp)
- [node-dir](https://www.npmjs.com/package/node-dir)
- [path-exists](https://www.npmjs.com/package/path-exists)
- [react](https://www.npmjs.com/package/react)
- [recursive-readdir](https://www.npmjs.com/package/recursive-readdir)
- [request](https://www.npmjs.com/package/request)
- [rimraf](https://www.npmjs.com/package/rimraf)
- [send](https://www.npmjs.com/package/send)
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
- [vinyl-fs](https://www.npmjs.com/package/vinyl-fs)
- [write-file-atomic](https://www.npmjs.com/package/write-file-atomic)
- [ws](https://github.com/websockets/ws)
## New queries
@@ -62,6 +76,10 @@
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. |
| Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. |
| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. |
| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. |
| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. |
## Changes to libraries

View File

@@ -12,6 +12,7 @@ import semmle.code.cpp.dataflow.DataFlow
*/
predicate allocExpr(Expr alloc, string kind) {
isAllocationExpr(alloc) and
not alloc.isFromUninstantiatedTemplate(_) and
(
alloc instanceof FunctionCall and
kind = "malloc"

View File

@@ -19,15 +19,19 @@ class ConstantZero extends Expr {
* Holds if `candidate` is an expression such that if it's unsigned then we
* want an alert at `ge`.
*/
private predicate lookForUnsignedAt(GEExpr ge, Expr candidate) {
// Base case: `candidate >= 0`
ge.getRightOperand() instanceof ConstantZero and
candidate = ge.getLeftOperand().getFullyConverted() and
// left operand was a signed or unsigned IntegralType before conversions
private predicate lookForUnsignedAt(RelationalOperation ge, Expr candidate) {
// Base case: `candidate >= 0` (or `0 <= candidate`)
(
ge instanceof GEExpr or
ge instanceof LEExpr
) and
ge.getLesserOperand() instanceof ConstantZero and
candidate = ge.getGreaterOperand().getFullyConverted() and
// left/greater operand was a signed or unsigned IntegralType before conversions
// (not a pointer, checking a pointer >= 0 is an entirely different mistake)
// (not an enum, as the fully converted type of an enum is compiler dependent
// so checking an enum >= 0 is always reasonable)
ge.getLeftOperand().getUnderlyingType() instanceof IntegralType
ge.getGreaterOperand().getUnderlyingType() instanceof IntegralType
or
// Recursive case: `...(largerType)candidate >= 0`
exists(Conversion conversion |
@@ -37,7 +41,7 @@ private predicate lookForUnsignedAt(GEExpr ge, Expr candidate) {
)
}
class UnsignedGEZero extends GEExpr {
class UnsignedGEZero extends ComparisonOperation {
UnsignedGEZero() {
exists(Expr ue |
lookForUnsignedAt(this, ue) and

View File

@@ -0,0 +1,138 @@
#include <stdlib.h>
#include <sys/param.h>
#include <unistd.h>
#include <pwd.h>
void callSetuidAndCheck(int uid) {
if (setuid(uid) != 0) {
exit(1);
}
}
void callSetgidAndCheck(int gid) {
if (setgid(gid) != 0) {
exit(1);
}
}
/// Correct ways to drop priv.
void correctDropPrivInline() {
if (setgroups(0, NULL)) {
exit(1);
}
if (setgid(-2) != 0) {
exit(1);
}
if (setuid(-2) != 0) {
exit(1);
}
}
void correctDropPrivInScope() {
{
if (setgroups(0, NULL)) {
exit(1);
}
}
{
if (setgid(-2) != 0) {
exit(1);
}
}
{
if (setuid(-2) != 0) {
exit(1);
}
}
}
void correctOrderForInitgroups() {
struct passwd *pw = getpwuid(0);
if (pw) {
if (initgroups(pw->pw_name, -2)) {
exit(1);
}
} else {
// Unhandled.
}
int rc = setuid(-2);
if (rc) {
exit(1);
}
}
void correctDropPrivInScopeParent() {
{
callSetgidAndCheck(-2);
}
correctOrderForInitgroups();
}
void incorrectNoReturnCodeCheck() {
int user = -2;
if (user) {
if (user) {
int rc = setgid(user);
(void)rc;
initgroups("nobody", user);
}
if (user) {
setuid(user);
}
}
}
void correctDropPrivInFunctionCall() {
if (setgroups(0, NULL)) {
exit(1);
}
callSetgidAndCheck(-2);
callSetuidAndCheck(-2);
}
/// Incorrect, out of order gid and uid.
/// Calling uid before gid will fail.
void incorrectDropPrivOutOfOrderInline() {
if (setuid(-2) != 0) {
exit(1);
}
if (setgid(-2) != 0) {
exit(1);
}
}
void incorrectDropPrivOutOfOrderInScope() {
{
if (setuid(-2) != 0) {
exit(1);
}
}
setgid(-2);
}
void incorrectDropPrivOutOfOrderWithFunction() {
callSetuidAndCheck(-2);
if (setgid(-2) != 0) {
exit(1);
}
}
void incorrectDropPrivOutOfOrderWithFunction2() {
callSetuidAndCheck(-2);
callSetgidAndCheck(-2);
}
void incorrectDropPrivNoCheck() {
setgid(-2);
setuid(-2);
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The code attempts to drop privilege in an incorrect order by
erroneous dropping user privilege before groups. This has security
impact if the return codes are not checked.</p>
<p>False positives include code performing negative checks, making
sure that setgid or setgroups does not work, meaning permissions are
dropped. Additionally, other forms of sandboxing may be present removing
any residual risk, for example a dedicated user namespace.</p>
</overview>
<recommendation>
<p>Set the new group ID, then set the target user's intended groups by
dropping previous supplemental source groups and initializing target
groups, and finally set the target user.</p>
</recommendation>
<example>
<p>The following example demonstrates out of order calls.</p>
<sample src="PrivilegeDroppingOutoforder.c" />
</example>
<references>
<li>CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/POS37-C.+Ensure+that+privilege+relinquishment+is+successful">POS37-C. Ensure that privilege relinquishment is successful</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,101 @@
/**
* @name LinuxPrivilegeDroppingOutoforder
* @description A syscall commonly associated with privilege dropping is being called out of order.
* Normally a process drops group ID and sets supplimental groups for the target user
* before setting the target user ID. This can have security impact if the return code
* from these methods is not checked.
* @kind problem
* @problem.severity recommendation
* @id cpp/drop-linux-privileges-outoforder
* @tags security
* external/cwe/cwe-273
* @precision medium
*/
import cpp
predicate argumentMayBeRoot(Expr e) {
e.getValue() = "0" or
e.(VariableAccess).getTarget().getName().toLowerCase().matches("%root%")
}
class SetuidLikeFunctionCall extends FunctionCall {
SetuidLikeFunctionCall() {
(getTarget().hasGlobalName("setuid") or getTarget().hasGlobalName("setresuid")) and
// setuid/setresuid with the root user are false positives.
not argumentMayBeRoot(getArgument(0))
}
}
class SetuidLikeWrapperCall extends FunctionCall {
SetuidLikeFunctionCall baseCall;
SetuidLikeWrapperCall() {
this = baseCall
or
exists(SetuidLikeWrapperCall fc |
this.getTarget() = fc.getEnclosingFunction() and
baseCall = fc.getBaseCall()
)
}
SetuidLikeFunctionCall getBaseCall() { result = baseCall }
}
class CallBeforeSetuidFunctionCall extends FunctionCall {
CallBeforeSetuidFunctionCall() {
(
getTarget().hasGlobalName("setgid") or
getTarget().hasGlobalName("setresgid") or
// Compatibility may require skipping initgroups and setgroups return checks.
// A stricter best practice is to check the result and errnor for EPERM.
getTarget().hasGlobalName("initgroups") or
getTarget().hasGlobalName("setgroups")
) and
// setgid/setresgid/etc with the root group are false positives.
not argumentMayBeRoot(getArgument(0))
}
}
class CallBeforeSetuidWrapperCall extends FunctionCall {
CallBeforeSetuidFunctionCall baseCall;
CallBeforeSetuidWrapperCall() {
this = baseCall
or
exists(CallBeforeSetuidWrapperCall fc |
this.getTarget() = fc.getEnclosingFunction() and
baseCall = fc.getBaseCall()
)
}
CallBeforeSetuidFunctionCall getBaseCall() { result = baseCall }
}
predicate setuidBeforeSetgid(
SetuidLikeWrapperCall setuidWrapper, CallBeforeSetuidWrapperCall setgidWrapper
) {
setgidWrapper.getAPredecessor+() = setuidWrapper
}
predicate isAccessed(FunctionCall fc) {
exists(Variable v | v.getAnAssignedValue() = fc)
or
exists(Operation c | fc = c.getAChild() | c.isCondition())
or
// ignore pattern where result is intentionally ignored by a cast to void.
fc.hasExplicitConversion()
}
from Function func, CallBeforeSetuidFunctionCall fc, SetuidLikeFunctionCall setuid
where
setuidBeforeSetgid(setuid, fc) and
// Require the call return code to be used in a condition or assigned.
// This introduces false negatives where the return is checked but then
// errno == EPERM allows execution to continue.
not isAccessed(fc) and
func = fc.getEnclosingFunction()
select fc,
"This function is called within " + func + ", and potentially after " +
"$@, and may not succeed. Be sure to check the return code and errno, otherwise permissions " +
"may not be dropped.", setuid, setuid.getTarget().getName()

View File

@@ -366,6 +366,49 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
}
}
/**
* A variable whose contents always have static storage duration. This can be a
* global variable, a namespace variable, a static local variable, or a static
* member variable.
*/
class StaticStorageDurationVariable extends Variable {
StaticStorageDurationVariable() {
this instanceof GlobalOrNamespaceVariable
or
this.(LocalVariable).isStatic()
or
this.(MemberVariable).isStatic()
}
/**
* Holds if the initializer for this variable is evaluated at compile time.
*/
predicate hasConstantInitialization() {
not runtimeExprInStaticInitializer(this.getInitializer().getExpr())
}
}
/**
* Holds if `e` is an expression in a static initializer that must be evaluated
* at run time. This predicate computes "is non-const" instead of "is const"
* since computing "is const" for an aggregate literal with many children would
* either involve recursion through `forall` on those children or an iteration
* through the rank numbers of the children, both of which can be slow.
*/
private predicate runtimeExprInStaticInitializer(Expr e) {
inStaticInitializer(e) and
if e instanceof AggregateLiteral
then runtimeExprInStaticInitializer(e.getAChild())
else not e.getFullyConverted().isConstant()
}
/** Holds if `e` is part of the initializer of a `StaticStorageDurationVariable`. */
private predicate inStaticInitializer(Expr e) {
exists(StaticStorageDurationVariable var | e = var.getInitializer().getExpr())
or
inStaticInitializer(e.getParent())
}
/**
* A C/C++ variable which has global scope or namespace scope. For example the
* variables `a` and `b` in the following code:

View File

@@ -443,8 +443,7 @@ private Node getControlOrderChildSparse(Node n, int i) {
private predicate skipInitializer(Initializer init) {
exists(LocalVariable local |
init = local.getInitializer() and
local.isStatic() and
not runtimeExprInStaticInitializer(init.getExpr())
local.(StaticStorageDurationVariable).hasConstantInitialization()
)
}

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -16,7 +16,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr {
override string getCanonicalQLClass() { result = "UnaryMinusExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -30,7 +30,7 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
override string getCanonicalQLClass() { result = "UnaryPlusExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -109,7 +109,7 @@ class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preinc
override string getCanonicalQLClass() { result = "PrefixIncrExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -125,7 +125,7 @@ class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predec
override string getCanonicalQLClass() { result = "PrefixDecrExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -141,7 +141,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post
override string getCanonicalQLClass() { result = "PostfixIncrExpr" }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + getOperator() }
}
@@ -159,7 +159,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post
override string getCanonicalQLClass() { result = "PostfixDecrExpr" }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + getOperator() }
}
@@ -210,7 +210,7 @@ class AddExpr extends BinaryArithmeticOperation, @addexpr {
override string getCanonicalQLClass() { result = "AddExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -224,7 +224,7 @@ class SubExpr extends BinaryArithmeticOperation, @subexpr {
override string getCanonicalQLClass() { result = "SubExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -238,7 +238,7 @@ class MulExpr extends BinaryArithmeticOperation, @mulexpr {
override string getCanonicalQLClass() { result = "MulExpr" }
override int getPrecedence() { result = 13 }
override int getPrecedence() { result = 14 }
}
/**
@@ -252,7 +252,7 @@ class DivExpr extends BinaryArithmeticOperation, @divexpr {
override string getCanonicalQLClass() { result = "DivExpr" }
override int getPrecedence() { result = 13 }
override int getPrecedence() { result = 14 }
}
/**
@@ -266,7 +266,7 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr {
override string getCanonicalQLClass() { result = "RemExpr" }
override int getPrecedence() { result = 13 }
override int getPrecedence() { result = 14 }
}
/**
@@ -283,7 +283,7 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
override string getCanonicalQLClass() { result = "ImaginaryMulExpr" }
override int getPrecedence() { result = 13 }
override int getPrecedence() { result = 14 }
}
/**
@@ -300,7 +300,7 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
override string getCanonicalQLClass() { result = "ImaginaryDivExpr" }
override int getPrecedence() { result = 13 }
override int getPrecedence() { result = 14 }
}
/**
@@ -318,7 +318,7 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -336,7 +336,7 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -354,7 +354,7 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
override string getCanonicalQLClass() { result = "RealImaginarySubExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -372,7 +372,7 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -416,7 +416,7 @@ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr {
override string getCanonicalQLClass() { result = "PointerAddExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -431,7 +431,7 @@ class PointerSubExpr extends PointerArithmeticOperation, @psubexpr {
override string getCanonicalQLClass() { result = "PointerSubExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}
/**
@@ -446,5 +446,5 @@ class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr {
override string getCanonicalQLClass() { result = "PointerDiffExpr" }
override int getPrecedence() { result = 12 }
override int getPrecedence() { result = 13 }
}

View File

@@ -14,7 +14,7 @@ class UnaryBitwiseOperation extends UnaryOperation, @un_bitwise_op_expr { }
class ComplementExpr extends UnaryBitwiseOperation, @complementexpr {
override string getOperator() { result = "~" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
override string getCanonicalQLClass() { result = "ComplementExpr" }
}
@@ -33,7 +33,7 @@ class BinaryBitwiseOperation extends BinaryOperation, @bin_bitwise_op_expr { }
class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr {
override string getOperator() { result = "<<" }
override int getPrecedence() { result = 11 }
override int getPrecedence() { result = 12 }
override string getCanonicalQLClass() { result = "LShiftExpr" }
}
@@ -47,7 +47,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr {
class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr {
override string getOperator() { result = ">>" }
override int getPrecedence() { result = 11 }
override int getPrecedence() { result = 12 }
override string getCanonicalQLClass() { result = "RShiftExpr" }
}

View File

@@ -74,7 +74,7 @@ abstract class Call extends Expr, NameQualifiableElement {
*/
abstract Function getTarget();
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
override string toString() { none() }

View File

@@ -84,7 +84,7 @@ class CStyleCast extends Cast, @c_style_cast {
override string getCanonicalQLClass() { result = "CStyleCast" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -103,7 +103,7 @@ class StaticCast extends Cast, @static_cast {
override string getCanonicalQLClass() { result = "StaticCast" }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
}
/**
@@ -121,7 +121,7 @@ class ConstCast extends Cast, @const_cast {
override string getCanonicalQLClass() { result = "ConstCast" }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
}
/**
@@ -139,7 +139,7 @@ class ReinterpretCast extends Cast, @reinterpret_cast {
override string getCanonicalQLClass() { result = "ReinterpretCast" }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
}
private predicate isArithmeticOrEnum(Type type) {
@@ -608,7 +608,7 @@ class PrvalueAdjustmentConversion extends Cast {
class DynamicCast extends Cast, @dynamic_cast {
override string toString() { result = "dynamic_cast<" + this.getType().getName() + ">..." }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
override string getCanonicalQLClass() { result = "DynamicCast" }
@@ -631,7 +631,7 @@ class UuidofOperator extends Expr, @uuidof {
else result = "__uuidof(0)"
}
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
/** Gets the contained type. */
Type getTypeOperand() { uuidof_bind(underlyingElement(this), unresolveElement(result)) }
@@ -669,7 +669,7 @@ class TypeidOperator extends Expr, @type_id {
override string toString() { result = "typeid ..." }
override int getPrecedence() { result = 16 }
override int getPrecedence() { result = 17 }
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }
@@ -700,7 +700,7 @@ class SizeofPackOperator extends Expr, @sizeof_pack {
* A C/C++ sizeof expression.
*/
abstract class SizeofOperator extends Expr, @runtime_sizeof {
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -763,7 +763,7 @@ class SizeofTypeOperator extends SizeofOperator {
* A C++11 `alignof` expression.
*/
abstract class AlignofOperator extends Expr, @runtime_alignof {
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**

View File

@@ -642,7 +642,7 @@ class AddressOfExpr extends UnaryOperation, @address_of {
override string getOperator() { result = "&" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
override predicate mayBeImpure() { this.getOperand().mayBeImpure() }
@@ -664,7 +664,7 @@ class ReferenceToExpr extends Conversion, @reference_to {
override string getCanonicalQLClass() { result = "ReferenceToExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**
@@ -687,7 +687,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect {
override string getOperator() { result = "*" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
override predicate mayBeImpure() {
this.getChild(0).mayBeImpure() or
@@ -721,7 +721,7 @@ class ReferenceDereferenceExpr extends Conversion, @ref_indirect {
* A C++ `new` or `new[]` expression.
*/
class NewOrNewArrayExpr extends Expr, @any_new_expr {
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
/**
* Gets the `operator new` or `operator new[]` that allocates storage.
@@ -898,7 +898,7 @@ class DeleteExpr extends Expr, @delete_expr {
override string getCanonicalQLClass() { result = "DeleteExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
/**
* Gets the compile-time type of the object being deleted.
@@ -972,7 +972,7 @@ class DeleteArrayExpr extends Expr, @delete_array_expr {
override string getCanonicalQLClass() { result = "DeleteArrayExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
/**
* Gets the element type of the array being deleted.
@@ -1216,3 +1216,18 @@ private predicate constantTemplateLiteral(Expr e) {
or
constantTemplateLiteral(e.(Cast).getExpr())
}
/**
* A C++ three-way comparison operation, also known as the _spaceship
* operation_. This is specific to C++20 and later.
* ```
* auto c = (a <=> b);
* ```
*/
class SpaceshipExpr extends BinaryOperation, @spaceshipexpr {
override string getCanonicalQLClass() { result = "SpaceshipExpr" }
override int getPrecedence() { result = 11 }
override string getOperator() { result = "<=>" }
}

View File

@@ -16,7 +16,7 @@ class NotExpr extends UnaryLogicalOperation, @notexpr {
override string getCanonicalQLClass() { result = "NotExpr" }
override int getPrecedence() { result = 15 }
override int getPrecedence() { result = 16 }
}
/**

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1,3 +1,275 @@
private import IR
import InstructionSanity
import IRTypeSanity
import InstructionSanity // module is below
import IRTypeSanity // module is in IRType.qll
module InstructionSanity {
private import internal.InstructionImports as Imports
private import Imports::OperandTag
private import internal.IRInternal
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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

@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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())
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.

View File

@@ -665,17 +665,18 @@ module DefUse {
private predicate definitionReachesRank(
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
) {
// The def always reaches the next use, even if there is also a def on the
// use instruction.
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
(
// The def always reaches the next use, even if there is also a def on the
// use instruction.
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
exists(int prevRank |
reachesRank = prevRank + 1 and
definitionReachesRank(useLocation, block, defRank, prevRank) and
not prevRank = exitRank(useLocation, block) and
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
)
}

View File

@@ -1,3 +1,275 @@
private import IR
import InstructionSanity
import IRTypeSanity
import InstructionSanity // module is below
import IRTypeSanity // module is in IRType.qll
module InstructionSanity {
private import internal.InstructionImports as Imports
private import Imports::OperandTag
private import internal.IRInternal
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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

@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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())
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.

View File

@@ -50,6 +50,14 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// constant value.
isIRConstant(getRealParent(expr))
or
// Only translate the initializer of a static local if it uses run-time data.
// Otherwise the initializer does not run in function scope.
exists(Initializer init, StaticStorageDurationVariable var |
init = var.getInitializer() and
var.hasConstantInitialization() and
expr = init.getExpr().getFullyConverted()
)
or
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
getRealParent(expr) instanceof AssumeExpr
or

View File

@@ -1,3 +1,275 @@
private import IR
import InstructionSanity
import IRTypeSanity
import InstructionSanity // module is below
import IRTypeSanity // module is in IRType.qll
module InstructionSanity {
private import internal.InstructionImports as Imports
private import Imports::OperandTag
private import internal.IRInternal
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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

@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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())
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.

View File

@@ -665,17 +665,18 @@ module DefUse {
private predicate definitionReachesRank(
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
) {
// The def always reaches the next use, even if there is also a def on the
// use instruction.
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
(
// The def always reaches the next use, even if there is also a def on the
// use instruction.
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
exists(int prevRank |
reachesRank = prevRank + 1 and
definitionReachesRank(useLocation, block, defRank, prevRank) and
not prevRank = exitRank(useLocation, block) and
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
)
}

View File

@@ -51,6 +51,7 @@ private import semmle.code.cpp.ir.IR
* methods.
*/
class GVN extends TValueNumber {
pragma[noinline]
GVN() {
exists(Instruction instr |
this = tvalueNumber(instr) and exists(instr.getUnconvertedResultExpression())

View File

@@ -91,13 +91,40 @@ private float wideningUpperBounds(ArithmeticType t) {
result = 1.0 / 0.0 // +Inf
}
/**
* Gets the value of the expression `e`, if it is a constant.
* This predicate also handles the case of constant variables initialized in different
* compilation units, which doesn't necessarily have a getValue() result from the extractor.
*/
private string getValue(Expr e) {
if exists(e.getValue())
then result = e.getValue()
else
/*
* It should be safe to propagate the initialization value to a variable if:
* The type of v is const, and
* The type of v is not volatile, and
* Either:
* v is a local/global variable, or
* v is a static member variable
*/
exists(VariableAccess access, StaticStorageDurationVariable v |
not v.getUnderlyingType().isVolatile() and
v.getUnderlyingType().isConst() and
e = access and
v = access.getTarget() and
result = getValue(v.getAnAssignedValue())
)
}
/** Set of expressions which we know how to analyze. */
private predicate analyzableExpr(Expr e) {
// The type of the expression must be arithmetic. We reuse the logic in
// `exprMinVal` to check this.
exists(exprMinVal(e)) and
(
exists(e.getValue().toFloat()) or
exists(getValue(e).toFloat()) or
e instanceof UnaryPlusExpr or
e instanceof UnaryMinusExpr or
e instanceof MinExpr or
@@ -365,8 +392,8 @@ private float getTruncatedLowerBounds(Expr expr) {
then
// If the expression evaluates to a constant, then there is no
// need to call getLowerBoundsImpl.
if exists(expr.getValue().toFloat())
then result = expr.getValue().toFloat()
if exists(getValue(expr).toFloat())
then result = getValue(expr).toFloat()
else (
// Some of the bounds computed by getLowerBoundsImpl might
// overflow, so we replace invalid bounds with exprMinVal.
@@ -418,8 +445,8 @@ private float getTruncatedUpperBounds(Expr expr) {
then
// If the expression evaluates to a constant, then there is no
// need to call getUpperBoundsImpl.
if exists(expr.getValue().toFloat())
then result = expr.getValue().toFloat()
if exists(getValue(expr).toFloat())
then result = getValue(expr).toFloat()
else (
// Some of the bounds computed by `getUpperBoundsImpl`
// might overflow, so we replace invalid bounds with

View File

@@ -99,6 +99,8 @@ class ArrayExecFunctionCall extends FunctionCall {
getTarget().hasGlobalName("execv") or
getTarget().hasGlobalName("execvp") or
getTarget().hasGlobalName("execvpe") or
getTarget().hasGlobalName("execve") or
getTarget().hasGlobalName("fexecve") or
// Windows variants
getTarget().hasGlobalName("_execv") or
getTarget().hasGlobalName("_execve") or

View File

@@ -13,19 +13,36 @@ predicate guardedAbs(Operation e, Expr use) {
)
}
/** This is `BasicBlock.getNode`, restricted to `Stmt` for performance. */
pragma[noinline]
private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt }
pragma[inline]
private predicate stmtDominates(Stmt dominator, Stmt dominated) {
// In same block
exists(BasicBlock block, int dominatorIndex, int dominatedIndex |
dominatorIndex = getStmtIndexInBlock(block, dominator) and
dominatedIndex = getStmtIndexInBlock(block, dominated) and
dominatedIndex >= dominatorIndex
)
or
// In (possibly) different blocks
bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock())
}
/** is the size of this use guarded to be less than something? */
pragma[nomagic]
predicate guardedLesser(Operation e, Expr use) {
exists(IfStmt c, RelationalOperation guard |
use = guard.getLesserOperand().getAChild*() and
guard = c.getControllingExpr().getAChild*() and
iDominates*(c.getThen(), e.getEnclosingStmt())
stmtDominates(c.getThen(), e.getEnclosingStmt())
)
or
exists(Loop c, RelationalOperation guard |
use = guard.getLesserOperand().getAChild*() and
guard = c.getControllingExpr().getAChild*() and
iDominates*(c.getStmt(), e.getEnclosingStmt())
stmtDominates(c.getStmt(), e.getEnclosingStmt())
)
or
exists(ConditionalExpr c, RelationalOperation guard |
@@ -43,13 +60,13 @@ predicate guardedGreater(Operation e, Expr use) {
exists(IfStmt c, RelationalOperation guard |
use = guard.getGreaterOperand().getAChild*() and
guard = c.getControllingExpr().getAChild*() and
iDominates*(c.getThen(), e.getEnclosingStmt())
stmtDominates(c.getThen(), e.getEnclosingStmt())
)
or
exists(Loop c, RelationalOperation guard |
use = guard.getGreaterOperand().getAChild*() and
guard = c.getControllingExpr().getAChild*() and
iDominates*(c.getStmt(), e.getEnclosingStmt())
stmtDominates(c.getStmt(), e.getEnclosingStmt())
)
or
exists(ConditionalExpr c, RelationalOperation guard |

View File

@@ -1231,6 +1231,7 @@ funbind(
| @ltexpr
| @geexpr
| @leexpr
| @spaceshipexpr
;
@bin_bitwise_op_expr = @lshiftexpr
@@ -1636,6 +1637,7 @@ case @expr.kind of
| 323 = @vec_fill
| 324 = @builtinconvertvector
| 325 = @builtincomplex
| 326 = @spaceshipexpr
;
new_allocated_type(

File diff suppressed because it is too large Load Diff

View File

@@ -8349,3 +8349,184 @@ perf-regression.cpp:
# 12| Type = [IntType] int
# 12| Value = [Literal] 0
# 12| ValueCategory = prvalue
struct_init.cpp:
# 1| [TopLevelFunction] int handler1(void*)
# 1| params:
# 1| 0: [Parameter] p
# 1| Type = [VoidPointerType] void *
# 2| [TopLevelFunction] int handler2(void*)
# 2| params:
# 2| 0: [Parameter] p
# 2| Type = [VoidPointerType] void *
# 4| [CopyAssignmentOperator] Info& Info::operator=(Info const&)
# 4| params:
#-----| 0: [Parameter] p#0
#-----| Type = [LValueReferenceType] const Info &
# 4| [MoveAssignmentOperator] Info& Info::operator=(Info&&)
# 4| params:
#-----| 0: [Parameter] p#0
#-----| Type = [RValueReferenceType] Info &&
# 16| [TopLevelFunction] void let_info_escape(Info*)
# 16| params:
# 16| 0: [Parameter] info
# 16| Type = [PointerType] Info *
# 16| body: [Block] { ... }
# 17| 0: [ExprStmt] ExprStmt
# 17| 0: [AssignExpr] ... = ...
# 17| Type = [PointerType] Info *
# 17| ValueCategory = lvalue
# 17| 0: [VariableAccess] global_pointer
# 17| Type = [PointerType] Info *
# 17| ValueCategory = lvalue
# 17| 1: [VariableAccess] info
# 17| Type = [PointerType] Info *
# 17| ValueCategory = prvalue(load)
# 18| 1: [ReturnStmt] return ...
# 20| [TopLevelFunction] void declare_static_infos()
# 20| params:
# 20| body: [Block] { ... }
# 21| 0: [DeclStmt] declaration
# 21| 0: [VariableDeclarationEntry] definition of static_infos
# 21| Type = [ArrayType] Info[]
# 21| init: [Initializer] initializer for static_infos
# 21| expr: [ArrayAggregateLiteral] {...}
# 21| Type = [ArrayType] Info[2]
# 21| ValueCategory = prvalue
# 22| [0]: [ClassAggregateLiteral] {...}
# 22| Type = [Struct] Info
# 22| ValueCategory = prvalue
# 22| .name: [ArrayToPointerConversion] array to pointer conversion
# 22| Type = [PointerType] const char *
# 22| ValueCategory = prvalue
# 22| expr: 1
# 22| Type = [ArrayType] const char[2]
# 22| Value = [StringLiteral] "1"
# 22| ValueCategory = lvalue
# 22| .handler: [FunctionAccess] handler1
# 22| Type = [FunctionPointerType] ..(*)(..)
# 22| ValueCategory = prvalue(load)
# 23| [1]: [ClassAggregateLiteral] {...}
# 23| Type = [Struct] Info
# 23| ValueCategory = prvalue
# 23| .name: [ArrayToPointerConversion] array to pointer conversion
# 23| Type = [PointerType] const char *
# 23| ValueCategory = prvalue
# 23| expr: 2
# 23| Type = [ArrayType] const char[2]
# 23| Value = [StringLiteral] "2"
# 23| ValueCategory = lvalue
# 23| .handler: [AddressOfExpr] & ...
# 23| Type = [FunctionPointerType] ..(*)(..)
# 23| ValueCategory = prvalue
# 23| 0: [FunctionAccess] handler2
# 23| Type = [RoutineType] ..()(..)
# 23| ValueCategory = lvalue
# 25| 1: [ExprStmt] ExprStmt
# 25| 0: [FunctionCall] call to let_info_escape
# 25| Type = [VoidType] void
# 25| ValueCategory = prvalue
# 25| 0: [ArrayToPointerConversion] array to pointer conversion
# 25| Type = [PointerType] Info *
# 25| ValueCategory = prvalue
# 25| expr: [VariableAccess] static_infos
# 25| Type = [ArrayType] Info[2]
# 25| ValueCategory = lvalue
# 26| 2: [ReturnStmt] return ...
# 28| [TopLevelFunction] void declare_local_infos()
# 28| params:
# 28| body: [Block] { ... }
# 29| 0: [DeclStmt] declaration
# 29| 0: [VariableDeclarationEntry] definition of local_infos
# 29| Type = [ArrayType] Info[]
# 29| init: [Initializer] initializer for local_infos
# 29| expr: [ArrayAggregateLiteral] {...}
# 29| Type = [ArrayType] Info[2]
# 29| ValueCategory = prvalue
# 30| [0]: [ClassAggregateLiteral] {...}
# 30| Type = [Struct] Info
# 30| ValueCategory = prvalue
# 30| .name: [ArrayToPointerConversion] array to pointer conversion
# 30| Type = [PointerType] const char *
# 30| ValueCategory = prvalue
# 30| expr: 1
# 30| Type = [ArrayType] const char[2]
# 30| Value = [StringLiteral] "1"
# 30| ValueCategory = lvalue
# 30| .handler: [FunctionAccess] handler1
# 30| Type = [FunctionPointerType] ..(*)(..)
# 30| ValueCategory = prvalue(load)
# 31| [1]: [ClassAggregateLiteral] {...}
# 31| Type = [Struct] Info
# 31| ValueCategory = prvalue
# 31| .name: [ArrayToPointerConversion] array to pointer conversion
# 31| Type = [PointerType] const char *
# 31| ValueCategory = prvalue
# 31| expr: 2
# 31| Type = [ArrayType] const char[2]
# 31| Value = [StringLiteral] "2"
# 31| ValueCategory = lvalue
# 31| .handler: [AddressOfExpr] & ...
# 31| Type = [FunctionPointerType] ..(*)(..)
# 31| ValueCategory = prvalue
# 31| 0: [FunctionAccess] handler2
# 31| Type = [RoutineType] ..()(..)
# 31| ValueCategory = lvalue
# 33| 1: [ExprStmt] ExprStmt
# 33| 0: [FunctionCall] call to let_info_escape
# 33| Type = [VoidType] void
# 33| ValueCategory = prvalue
# 33| 0: [ArrayToPointerConversion] array to pointer conversion
# 33| Type = [PointerType] Info *
# 33| ValueCategory = prvalue
# 33| expr: [VariableAccess] local_infos
# 33| Type = [ArrayType] Info[2]
# 33| ValueCategory = lvalue
# 34| 2: [ReturnStmt] return ...
# 36| [TopLevelFunction] void declare_static_runtime_infos(char const*)
# 36| params:
# 36| 0: [Parameter] name1
# 36| Type = [PointerType] const char *
# 36| body: [Block] { ... }
# 37| 0: [DeclStmt] declaration
# 37| 0: [VariableDeclarationEntry] definition of static_infos
# 37| Type = [ArrayType] Info[]
# 37| init: [Initializer] initializer for static_infos
# 37| expr: [ArrayAggregateLiteral] {...}
# 37| Type = [ArrayType] Info[2]
# 37| ValueCategory = prvalue
# 38| [0]: [ClassAggregateLiteral] {...}
# 38| Type = [Struct] Info
# 38| ValueCategory = prvalue
# 38| .name: [VariableAccess] name1
# 38| Type = [PointerType] const char *
# 38| ValueCategory = prvalue(load)
# 38| .handler: [FunctionAccess] handler1
# 38| Type = [FunctionPointerType] ..(*)(..)
# 38| ValueCategory = prvalue(load)
# 39| [1]: [ClassAggregateLiteral] {...}
# 39| Type = [Struct] Info
# 39| ValueCategory = prvalue
# 39| .name: [ArrayToPointerConversion] array to pointer conversion
# 39| Type = [PointerType] const char *
# 39| ValueCategory = prvalue
# 39| expr: 2
# 39| Type = [ArrayType] const char[2]
# 39| Value = [StringLiteral] "2"
# 39| ValueCategory = lvalue
# 39| .handler: [AddressOfExpr] & ...
# 39| Type = [FunctionPointerType] ..(*)(..)
# 39| ValueCategory = prvalue
# 39| 0: [FunctionAccess] handler2
# 39| Type = [RoutineType] ..()(..)
# 39| ValueCategory = lvalue
# 41| 1: [ExprStmt] ExprStmt
# 41| 0: [FunctionCall] call to let_info_escape
# 41| Type = [VoidType] void
# 41| ValueCategory = prvalue
# 41| 0: [ArrayToPointerConversion] array to pointer conversion
# 41| Type = [PointerType] Info *
# 41| ValueCategory = prvalue
# 41| expr: [VariableAccess] static_infos
# 41| Type = [ArrayType] Info[2]
# 41| ValueCategory = lvalue
# 42| 2: [ReturnStmt] return ...

View File

@@ -6272,3 +6272,131 @@ perf-regression.cpp:
# 9| v9_7(void) = UnmodeledUse : mu*
# 9| v9_8(void) = AliasedUse : ~mu9_4
# 9| v9_9(void) = ExitFunction :
struct_init.cpp:
# 16| void let_info_escape(Info*)
# 16| Block 0
# 16| v16_1(void) = EnterFunction :
# 16| mu16_2(unknown) = AliasedDefinition :
# 16| mu16_3(unknown) = InitializeNonLocal :
# 16| mu16_4(unknown) = UnmodeledDefinition :
# 16| r16_5(glval<Info *>) = VariableAddress[info] :
# 16| mu16_6(Info *) = InitializeParameter[info] : &:r16_5
# 16| r16_7(Info *) = Load : &:r16_5, ~mu16_6
# 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7
# 17| r17_1(glval<Info *>) = VariableAddress[info] :
# 17| r17_2(Info *) = Load : &:r17_1, ~mu16_4
# 17| r17_3(glval<Info *>) = VariableAddress[global_pointer] :
# 17| mu17_4(Info *) = Store : &:r17_3, r17_2
# 18| v18_1(void) = NoOp :
# 16| v16_9(void) = ReturnIndirection : &:r16_7, ~mu16_4
# 16| v16_10(void) = ReturnVoid :
# 16| v16_11(void) = UnmodeledUse : mu*
# 16| v16_12(void) = AliasedUse : ~mu16_4
# 16| v16_13(void) = ExitFunction :
# 20| void declare_static_infos()
# 20| Block 0
# 20| v20_1(void) = EnterFunction :
# 20| mu20_2(unknown) = AliasedDefinition :
# 20| mu20_3(unknown) = InitializeNonLocal :
# 20| mu20_4(unknown) = UnmodeledDefinition :
# 21| r21_1(glval<Info[2]>) = VariableAddress[static_infos] :
# 21| mu21_2(Info[2]) = Uninitialized[static_infos] : &:r21_1
# 25| r25_1(glval<unknown>) = FunctionAddress[let_info_escape] :
# 25| r25_2(glval<Info[2]>) = VariableAddress[static_infos] :
# 25| r25_3(Info *) = Convert : r25_2
# 25| v25_4(void) = Call : func:r25_1, 0:r25_3
# 25| mu25_5(unknown) = ^CallSideEffect : ~mu20_4
# 25| v25_6(void) = ^BufferReadSideEffect[0] : &:r25_3, ~mu20_4
# 25| mu25_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r25_3
# 26| v26_1(void) = NoOp :
# 20| v20_5(void) = ReturnVoid :
# 20| v20_6(void) = UnmodeledUse : mu*
# 20| v20_7(void) = AliasedUse : ~mu20_4
# 20| v20_8(void) = ExitFunction :
# 28| void declare_local_infos()
# 28| Block 0
# 28| v28_1(void) = EnterFunction :
# 28| mu28_2(unknown) = AliasedDefinition :
# 28| mu28_3(unknown) = InitializeNonLocal :
# 28| mu28_4(unknown) = UnmodeledDefinition :
# 29| r29_1(glval<Info[2]>) = VariableAddress[local_infos] :
# 29| mu29_2(Info[2]) = Uninitialized[local_infos] : &:r29_1
# 29| r29_3(int) = Constant[0] :
# 29| r29_4(glval<Info>) = PointerAdd[16] : r29_1, r29_3
# 30| r30_1(glval<char *>) = FieldAddress[name] : r29_4
# 30| r30_2(glval<char[2]>) = StringConstant["1"] :
# 30| r30_3(char *) = Convert : r30_2
# 30| mu30_4(char *) = Store : &:r30_1, r30_3
# 30| r30_5(glval<..(*)(..)>) = FieldAddress[handler] : r29_4
# 30| r30_6(..(*)(..)) = FunctionAddress[handler1] :
# 30| mu30_7(..(*)(..)) = Store : &:r30_5, r30_6
# 29| r29_5(int) = Constant[1] :
# 29| r29_6(glval<Info>) = PointerAdd[16] : r29_1, r29_5
# 31| r31_1(glval<char *>) = FieldAddress[name] : r29_6
# 31| r31_2(glval<char[2]>) = StringConstant["2"] :
# 31| r31_3(char *) = Convert : r31_2
# 31| mu31_4(char *) = Store : &:r31_1, r31_3
# 31| r31_5(glval<..(*)(..)>) = FieldAddress[handler] : r29_6
# 31| r31_6(glval<..()(..)>) = FunctionAddress[handler2] :
# 31| r31_7(..(*)(..)) = CopyValue : r31_6
# 31| mu31_8(..(*)(..)) = Store : &:r31_5, r31_7
# 33| r33_1(glval<unknown>) = FunctionAddress[let_info_escape] :
# 33| r33_2(glval<Info[2]>) = VariableAddress[local_infos] :
# 33| r33_3(Info *) = Convert : r33_2
# 33| v33_4(void) = Call : func:r33_1, 0:r33_3
# 33| mu33_5(unknown) = ^CallSideEffect : ~mu28_4
# 33| v33_6(void) = ^BufferReadSideEffect[0] : &:r33_3, ~mu28_4
# 33| mu33_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r33_3
# 34| v34_1(void) = NoOp :
# 28| v28_5(void) = ReturnVoid :
# 28| v28_6(void) = UnmodeledUse : mu*
# 28| v28_7(void) = AliasedUse : ~mu28_4
# 28| v28_8(void) = ExitFunction :
# 36| void declare_static_runtime_infos(char const*)
# 36| Block 0
# 36| v36_1(void) = EnterFunction :
# 36| mu36_2(unknown) = AliasedDefinition :
# 36| mu36_3(unknown) = InitializeNonLocal :
# 36| mu36_4(unknown) = UnmodeledDefinition :
# 36| r36_5(glval<char *>) = VariableAddress[name1] :
# 36| mu36_6(char *) = InitializeParameter[name1] : &:r36_5
# 36| r36_7(char *) = Load : &:r36_5, ~mu36_6
# 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7
# 37| r37_1(glval<Info[2]>) = VariableAddress[static_infos] :
# 37| mu37_2(Info[2]) = Uninitialized[static_infos] : &:r37_1
# 37| r37_3(int) = Constant[0] :
# 37| r37_4(glval<Info>) = PointerAdd[16] : r37_1, r37_3
# 38| r38_1(glval<char *>) = FieldAddress[name] : r37_4
# 38| r38_2(glval<char *>) = VariableAddress[name1] :
# 38| r38_3(char *) = Load : &:r38_2, ~mu36_4
# 38| mu38_4(char *) = Store : &:r38_1, r38_3
# 38| r38_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_4
# 38| r38_6(..(*)(..)) = FunctionAddress[handler1] :
# 38| mu38_7(..(*)(..)) = Store : &:r38_5, r38_6
# 37| r37_5(int) = Constant[1] :
# 37| r37_6(glval<Info>) = PointerAdd[16] : r37_1, r37_5
# 39| r39_1(glval<char *>) = FieldAddress[name] : r37_6
# 39| r39_2(glval<char[2]>) = StringConstant["2"] :
# 39| r39_3(char *) = Convert : r39_2
# 39| mu39_4(char *) = Store : &:r39_1, r39_3
# 39| r39_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_6
# 39| r39_6(glval<..()(..)>) = FunctionAddress[handler2] :
# 39| r39_7(..(*)(..)) = CopyValue : r39_6
# 39| mu39_8(..(*)(..)) = Store : &:r39_5, r39_7
# 41| r41_1(glval<unknown>) = FunctionAddress[let_info_escape] :
# 41| r41_2(glval<Info[2]>) = VariableAddress[static_infos] :
# 41| r41_3(Info *) = Convert : r41_2
# 41| v41_4(void) = Call : func:r41_1, 0:r41_3
# 41| mu41_5(unknown) = ^CallSideEffect : ~mu36_4
# 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~mu36_4
# 41| mu41_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r41_3
# 42| v42_1(void) = NoOp :
# 36| v36_9(void) = ReturnIndirection : &:r36_7, ~mu36_4
# 36| v36_10(void) = ReturnVoid :
# 36| v36_11(void) = UnmodeledUse : mu*
# 36| v36_12(void) = AliasedUse : ~mu36_4
# 36| v36_13(void) = ExitFunction :

View File

@@ -0,0 +1,42 @@
int handler1(void *p);
int handler2(void *p);
struct Info {
const char *name;
int (*handler)(void *);
};
static Info infos_in_file[] = {
{ "1", handler1 },
{ "3", &handler2 },
};
Info *global_pointer;
void let_info_escape(Info *info) {
global_pointer = info;
}
void declare_static_infos() {
static Info static_infos[] = {
{ "1", handler1 },
{ "2", &handler2 },
};
let_info_escape(static_infos);
}
void declare_local_infos() {
Info local_infos[] = {
{ "1", handler1 },
{ "2", &handler2 },
};
let_info_escape(local_infos);
}
void declare_static_runtime_infos(const char *name1) {
static Info static_infos[] = {
{ name1, handler1 },
{ "2", &handler2 },
};
let_info_escape(static_infos);
}

View File

@@ -0,0 +1,16 @@
// This header file is extracted only once even though it's included by both
// file1.c and file2.c. That's presumably because it's wrongly considered to
// expand to the same trap in both contexts. In practice, this header gets
// extracted together with the extraction of file1.c.
// BUG: types of members depend on extraction order.
// Only one copy of this struct is extracted, and the types of its members refer
// to the typedefs in file1.c. Had file2.c been extracted first instead, the
// types of its members would be different.
struct UnifiableOnce {
intAlias intMember;
qualifiedIntAlias qualifiedIntMember;
};
// BUG: types of parameters depend on extraction order.
void functionOnce(intAlias param);

View File

@@ -0,0 +1,30 @@
// This header file is extracted twice because its inclusions in file1.c and
// file2.c lead to different context hashes, seemingly because this file (unlike
// extracted_once.h) refers to `structAlias`. That means the resulting trap has
// two copies of all declarations in this file, and those copies have to be
// unified in the trap import step or in QL.
// GOOD. The types of the members of this struct are unifiable, which in this
// context means that they share the same unspecified types. This means that the
// two extractions of the struct get the same content hash and therefore become
// one entry in the database. Both struct members have multiple types in the
// `membervariables` table, but those are unified in the
// `MemberVariable.getType()` predicate.
struct UnifiableTwice {
intAlias intMember;
qualifiedIntAlias qualifiedIntMember;
};
// BUG: Non-member variables of this type have two types in the database.
// The type of `structMember` is ambiguous, and the two possible types are not
// unifiable, meaning in this context that they don't share an unspecified type.
// The types are nevertheless _compatible_, so it's valid C (not C++) to use
// these two definitions interchangably in the same program.
struct NotUnifiableTwice {
structAlias structMember;
};
// BUG: The parameter of this function has two types.
// Because the `MemberVariable.getType()` workaround does not apply to a
// `Parameter`, this `Parameter` gets two types.
void functionTwice(intAlias param);

View File

@@ -0,0 +1,15 @@
// These typedefs are all _compatible_ (see
// https://en.cppreference.com/w/c/language/type#Compatible_types) with their
// siblings in file2.c. It varies whether they have a canonical form that's
// common to them both.
typedef int localInt;
typedef localInt intAlias; // has common `getUnderlyingType()` and `getUnspecifiedType()`
typedef int qualifiedIntAlias; // only has common `getUnspecifiedType()`
typedef struct emptyStruct1 { } structAlias; // has no common type
#include "extracted_once.h"
struct UnifiableOnce uOnce;
#include "extracted_twice.h"
struct UnifiableTwice uTwice;
struct NotUnifiableTwice nTwice; // BUG: this variable has two types

View File

@@ -0,0 +1,10 @@
typedef int intAlias;
typedef const int qualifiedIntAlias;
typedef struct emptyStruct2 { } structAlias;
#include "extracted_once.h"
struct UnifiableOnce uOnce;
#include "extracted_twice.h"
struct UnifiableTwice uTwice;
struct NotUnifiableTwice nTwice; // BUG: this variable has two types

View File

@@ -0,0 +1,17 @@
| extracted_once.h:11:14:11:22 | intMember | file1.c:6:18:6:25 | intAlias | 1 |
| extracted_once.h:12:23:12:40 | qualifiedIntMember | file1.c:7:13:7:29 | qualifiedIntAlias | 1 |
| extracted_once.h:16:28:16:32 | param | file1.c:6:18:6:25 | intAlias | 1 |
| extracted_twice.h:14:14:14:22 | intMember | file://:0:0:0:0 | int | 1 |
| extracted_twice.h:15:23:15:40 | qualifiedIntMember | file://:0:0:0:0 | int | 1 |
| extracted_twice.h:24:17:24:28 | structMember | file1.c:8:33:8:43 | structAlias | 1 |
| extracted_twice.h:24:17:24:28 | structMember | file2.c:3:33:3:43 | structAlias | 1 |
| extracted_twice.h:30:29:30:33 | param | file1.c:6:18:6:25 | intAlias | 2 |
| extracted_twice.h:30:29:30:33 | param | file2.c:1:13:1:20 | intAlias | 2 |
| file1.c:11:22:11:26 | uOnce | extracted_once.h:10:8:10:20 | UnifiableOnce | 1 |
| file1.c:14:23:14:28 | uTwice | extracted_twice.h:13:8:13:21 | UnifiableTwice | 1 |
| file1.c:15:26:15:31 | nTwice | extracted_twice.h:23:8:23:24 | NotUnifiableTwice | 2 |
| file1.c:15:26:15:31 | nTwice | extracted_twice.h:23:8:23:24 | NotUnifiableTwice | 2 |
| file2.c:6:22:6:26 | uOnce | extracted_once.h:10:8:10:20 | UnifiableOnce | 1 |
| file2.c:9:23:9:28 | uTwice | extracted_twice.h:13:8:13:21 | UnifiableTwice | 1 |
| file2.c:10:26:10:31 | nTwice | extracted_twice.h:23:8:23:24 | NotUnifiableTwice | 2 |
| file2.c:10:26:10:31 | nTwice | extracted_twice.h:23:8:23:24 | NotUnifiableTwice | 2 |

View File

@@ -0,0 +1,5 @@
import cpp
from Variable var
where exists(var.getFile().getRelativePath())
select var, var.getType(), strictcount(var.getType())

View File

@@ -137,8 +137,12 @@
| test.c:109:14:109:16 | Constant: 44 | positive strictlyPositive |
| test.c:110:14:110:14 | Constant: 1 | positive strictlyPositive |
| test.c:110:14:110:14 | Store: 1 | positive strictlyPositive |
| test.c:118:20:118:20 | Uninitialized: definition of n | positive |
| test.c:119:10:119:10 | Load: n | positive |
| test.c:119:10:119:12 | Add: ... ++ | positive strictlyPositive |
| test.c:119:10:119:12 | Constant: ... ++ | positive strictlyPositive |
| test.c:119:10:119:12 | CopyValue: ... ++ | positive |
| test.c:119:10:119:12 | Store: ... ++ | positive |
| test.c:119:10:119:12 | Store: ... ++ | positive strictlyPositive |
| test.c:124:11:124:15 | Load: Start | positive |
| test.c:124:11:124:15 | Phi: Start | positive |

View File

@@ -47,7 +47,6 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:11:12:11:15 | Chi: call to C |
| ms_try_mix.cpp:28:12:28:15 | Chi: call to C |
| ms_try_mix.cpp:48:10:48:13 | Chi: call to C |
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... |
| vla.c:5:9:5:14 | Uninitialized: definition of matrix |
| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef |

View File

@@ -34,8 +34,6 @@ missingOperand
| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| pointer_to_member.cpp:36:13:36:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
| pointer_to_member.cpp:36:22:36:28 | Store: f1 | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
| range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
| range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
| range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
@@ -93,16 +91,6 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C |
| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... |
| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } |
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
| static_init_templates.cpp:89:27:89:36 | Convert: (void *)... |
| static_init_templates.cpp:89:27:89:36 | Convert: (void *)... |
| static_init_templates.cpp:97:27:97:36 | Convert: (void *)... |
| static_init_templates.cpp:97:27:97:36 | Convert: (void *)... |
| static_init_templates.cpp:105:27:105:27 | Constant: (void *)... |
| static_init_templates.cpp:105:27:105:27 | Constant: (void *)... |
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... |
| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) |
| stmt_in_type.cpp:5:53:5:53 | Constant: 1 |
@@ -640,9 +628,6 @@ backEdgeCountMismatch
useNotDominatedByDefinition
| VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | IR: CallDestructor | void CallDestructor<int>(int, int*) |
| misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| pointer_to_member.cpp:36:11:36:30 | Unary | Operand 'Unary' 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:13:36:19 | 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) |
| 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

View File

@@ -56,7 +56,6 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C |
| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C |
| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C |
| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} |
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... |
| vla.c:5:9:5:14 | Uninitialized: definition of matrix |
| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef |

View File

@@ -7,37 +7,65 @@
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const address & | SemanticStackVariable | | |
| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | Field | | |
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
| variables.cpp:5:11:5:11 | c | file://:0:0:0:0 | const int | GlobalVariable | const | static |
| variables.cpp:5:11:5:11 | c | file://:0:0:0:0 | const int | StaticStorageDurationVariable | const | static |
| variables.cpp:6:14:6:15 | pi | file://:0:0:0:0 | const double | GlobalVariable | const | static |
| variables.cpp:6:14:6:15 | pi | file://:0:0:0:0 | const double | StaticStorageDurationVariable | const | static |
| variables.cpp:8:10:8:10 | a | file://:0:0:0:0 | unsigned int | GlobalVariable | | |
| variables.cpp:8:10:8:10 | a | file://:0:0:0:0 | unsigned int | StaticStorageDurationVariable | | |
| variables.cpp:10:14:10:14 | b | file://:0:0:0:0 | unsigned int | GlobalVariable | | |
| variables.cpp:10:14:10:14 | b | file://:0:0:0:0 | unsigned int | StaticStorageDurationVariable | | |
| variables.cpp:12:13:12:17 | kings | file://:0:0:0:0 | const char *[] | GlobalVariable | | |
| variables.cpp:12:13:12:17 | kings | file://:0:0:0:0 | const char *[] | StaticStorageDurationVariable | | |
| variables.cpp:14:6:14:6 | p | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:14:6:14:6 | p | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
| variables.cpp:14:9:14:9 | q | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:14:9:14:9 | q | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |
| variables.cpp:15:12:15:13 | v1 | file://:0:0:0:0 | int[10] | GlobalVariable | | static |
| variables.cpp:15:12:15:13 | v1 | file://:0:0:0:0 | int[10] | StaticStorageDurationVariable | | static |
| variables.cpp:15:21:15:22 | pv | file://:0:0:0:0 | int * | GlobalVariable | | static |
| variables.cpp:15:21:15:22 | pv | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | static |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | FunctionPointerVariable | | |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | GlobalVariable | | |
| variables.cpp:17:7:17:8 | fp | file://:0:0:0:0 | ..(*)(..) | StaticStorageDurationVariable | | |
| variables.cpp:19:7:19:8 | v2 | file://:0:0:0:0 | float[3] | GlobalVariable | | |
| variables.cpp:19:7:19:8 | v2 | file://:0:0:0:0 | float[3] | StaticStorageDurationVariable | | |
| variables.cpp:20:7:20:8 | v3 | file://:0:0:0:0 | char *[32] | GlobalVariable | | |
| variables.cpp:20:7:20:8 | v3 | file://:0:0:0:0 | char *[32] | StaticStorageDurationVariable | | |
| variables.cpp:22:5:22:6 | d2 | file://:0:0:0:0 | int[10][20] | GlobalVariable | | |
| variables.cpp:22:5:22:6 | d2 | file://:0:0:0:0 | int[10][20] | StaticStorageDurationVariable | | |
| variables.cpp:24:6:24:7 | v4 | file://:0:0:0:0 | char[3] | GlobalVariable | | |
| variables.cpp:24:6:24:7 | v4 | file://:0:0:0:0 | char[3] | StaticStorageDurationVariable | | |
| variables.cpp:26:5:26:6 | v5 | file://:0:0:0:0 | int[8] | GlobalVariable | | |
| variables.cpp:26:5:26:6 | v5 | file://:0:0:0:0 | int[8] | StaticStorageDurationVariable | | |
| variables.cpp:28:7:28:8 | p2 | file://:0:0:0:0 | char * | GlobalVariable | | |
| variables.cpp:28:7:28:8 | p2 | file://:0:0:0:0 | char * | StaticStorageDurationVariable | | |
| variables.cpp:29:6:29:7 | p3 | file://:0:0:0:0 | char[] | GlobalVariable | | |
| variables.cpp:29:6:29:7 | p3 | file://:0:0:0:0 | char[] | StaticStorageDurationVariable | | |
| variables.cpp:31:6:31:10 | alpha | file://:0:0:0:0 | char[] | GlobalVariable | | |
| variables.cpp:31:6:31:10 | alpha | file://:0:0:0:0 | char[] | StaticStorageDurationVariable | | |
| variables.cpp:34:5:34:6 | av | file://:0:0:0:0 | int[] | GlobalVariable | | |
| variables.cpp:34:5:34:6 | av | file://:0:0:0:0 | int[] | StaticStorageDurationVariable | | |
| variables.cpp:35:6:35:8 | ap1 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:35:6:35:8 | ap1 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
| variables.cpp:36:6:36:8 | ap2 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:36:6:36:8 | ap2 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalVariable | | |
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | StaticStorageDurationVariable | | |
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable | | |
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | SemanticStackVariable | | |
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | LocalVariable | | static |
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | StaticStorageDurationVariable | | static |
| variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | Field | | |
| variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | Field | | |
| variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | Field | | |
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable | | static |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | StaticStorageDurationVariable | | static |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalVariable | | |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | StaticStorageDurationVariable | | |

View File

@@ -1,3 +1,5 @@
| test2.cpp:19:3:19:6 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:18:12:18:18 | new | new |
| test2.cpp:26:3:26:6 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:25:7:25:13 | new | new |
| test.cpp:36:2:36:17 | delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test.cpp:27:18:27:23 | call to malloc | malloc |
| test.cpp:41:2:41:5 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test.cpp:26:7:26:17 | new | new |
| test.cpp:68:3:68:11 | delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test.cpp:64:28:64:33 | call to malloc | malloc |

View File

@@ -0,0 +1,36 @@
// semmle-extractor-options: -std=gnu++14
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
void* operator new(size_t _Size, void *_Where);
// ---
template<typename T>
class MyTest2Class
{
public:
MyTest2Class()
{
int *a = new int;
free(a); // BAD
int *ptr_b = (int *)malloc(sizeof(int));
int *b = new(ptr_b) int;
free(b); // GOOD
c = new int;
free(c); // BAD
int *ptr_d = (int *)malloc(sizeof(int));
d = new(ptr_d) int;
free(d); // GOOD
}
int *c, *d;
};
MyTest2Class<int> mt2c_i;

View File

@@ -0,0 +1,29 @@
void func_with_default_arg(const int n = 0) {
if(n <= 10) {}
}
struct A {
const int int_member = 0;
A(int n) : int_member(n) {
if(int_member <= 10) {
}
}
};
struct B {
B(const int n = 0) {
if(n <= 10) {}
}
};
const volatile int volatile_const_global = 0;
void test1() {
func_with_default_arg(100);
A a(100);
if(a.int_member <= 10) {}
if(volatile_const_global <= 10) {}
}

View File

@@ -112,4 +112,29 @@ void myFunction() {
assert(CHECK_RANGE(ui, 0, 10)); // reasonable use
assert(UI >= ZERO); // violation (not detected)
assert(ui GE 0); // violation
if ((unsigned char)si >= 0) { // violation
}
if ((unsigned char)(signed int)si >= 0) { // violation
}
if ((signed int)(unsigned char)si >= 0) { // violation
}
if ((unsigned char)(signed char)si >= 0) { // violation
}
if ((signed char)(unsigned char)si >= 0) {
}
if ((signed int)(unsigned char)(signed int)si >= 0) { // violation
}
if ((signed char)(unsigned char)(signed int)si >= 0) {
}
if ((signed int)(unsigned char)(signed char)si >= 0) { // violation
}
if (ui <= 0) {
}
if (0 <= ui) { // violation
}
if (0 < ui) {
}
}

View File

@@ -112,4 +112,29 @@ void myFunction() {
assert(CHECK_RANGE(ui, 0, 10)); // reasonable use
assert(UI >= ZERO); // violation (not detected)
assert(ui GE 0); // violation
if ((unsigned char)si >= 0) { // violation
}
if ((unsigned char)(signed int)si >= 0) { // violation
}
if ((signed int)(unsigned char)si >= 0) { // violation
}
if ((unsigned char)(signed char)si >= 0) { // violation
}
if ((signed char)(unsigned char)si >= 0) {
}
if ((signed int)(unsigned char)(signed int)si >= 0) { // violation
}
if ((signed char)(unsigned char)(signed int)si >= 0) {
}
if ((signed int)(unsigned char)(signed char)si >= 0) { // violation
}
if (ui <= 0) {
}
if (0 <= ui) { // violation
}
if (0 < ui) {
}
}

View File

@@ -14,6 +14,13 @@
| UnsignedGEZero.c:101:9:101:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:111:9:111:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:114:9:114:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:116:6:116:27 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:118:6:118:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:120:6:120:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:122:6:122:40 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:127:6:127:51 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:131:6:131:52 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.c:136:6:136:12 | ... <= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:40:6:40:12 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:48:6:48:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:54:6:54:12 | ... >= ... | Pointless comparison of unsigned value to zero. |
@@ -29,3 +36,10 @@
| UnsignedGEZero.cpp:101:9:101:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:111:9:111:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:114:9:114:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:116:6:116:27 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:118:6:118:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:120:6:120:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:122:6:122:40 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:127:6:127:51 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:131:6:131:52 | ... >= ... | Pointless comparison of unsigned value to zero. |
| UnsignedGEZero.cpp:136:6:136:12 | ... <= ... | Pointless comparison of unsigned value to zero. |

View File

@@ -6,3 +6,4 @@
| 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:127:17:127:22 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:123:25:123:30 | call to getenv | user input (getenv) |

View File

@@ -105,3 +105,24 @@ void processFile()
fclose(f);
}
}
char *getenv(const char *name);
#define MAX_SIZE 500
int bounded(int x, int limit) {
int result = x;
if (x <= 0)
result = 1;
else if (x > limit)
result = limit;
return result;
}
void open_file_bounded () {
int size = size = atoi(getenv("USER"));
int bounded_size = bounded(size, MAX_SIZE);
int* a = (int*)malloc(bounded_size); // GOOD
int* b = (int*)malloc(size); // BAD
}

View File

@@ -69,3 +69,10 @@ void test10(int x) {
} while (0);
}
}
extern const int const256;
void test11() {
short s;
for(s = 0; s < const256; ++s) {}
}

View File

@@ -0,0 +1 @@
const int const256 = 256;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add support for C++'s <=> operator
compatibility: backwards

View File

@@ -50,7 +50,7 @@ namespace Semmle.Autobuild
var build = GetBuildScript(builder, dotNetPath, environment, compatibleClr, projectOrSolution.FullPath);
ret &= clean & BuildScript.Try(restore) & build;
ret &= BuildScript.Try(clean) & BuildScript.Try(restore) & build;
}
return ret;
});

View File

@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.IO;
using System.Linq;
@@ -13,16 +14,12 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(ContainingType);
trapFile.Write(".");
trapFile.WriteSubId(Location);
if (symbol.IsGenericMethod && !IsSourceDeclaration)
{
trapFile.Write('<');
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
trapFile.Write('>');
}
trapFile.Write(";localfunction");
throw new InvalidOperationException();
}
public override void WriteQuotedId(TextWriter trapFile)
{
trapFile.Write('*');
}
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field);

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowStep(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
additionalLocalFlowStep(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
nodeCand(TNormalNode(node2), unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(TNormalNode(node2), unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
nodeCand(TNormalNode(node2), unbind(config))
)
)
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
*/
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, config)
}
pragma[nomagic]
private predicate localFlowBigStepExt(
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
) {
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
}
private newtype TAccessPathFront =
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
else any()
}
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathFrontNilNode extends NormalNodeExt {
AccessPathFrontNilNode() {
nodeCand(this, _) and
(
any(Configuration c).isSource(this.getNode())
or
localFlowBigStepExt(_, this, false, _)
or
additionalJumpStepExt(_, this, _)
)
}
/** Gets the `nil` path front for this node. */
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
}
private predicate flowCandFwd0(
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
) {
nodeCand2(node, _, false, config) and
config.isSource(node.getNode()) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
or
nodeCand(node, unbind(config)) and
(
exists(NodeExt mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
apf = node.(AccessPathFrontNilNode).getApf()
localFlowBigStepExt(mid, node, false, apf, config)
)
or
exists(NodeExt mid |
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
flowCandFwd(mid, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
apf = node.(AccessPathFrontNilNode).getApf()
apf = TFrontNil(node.getErasedNodeTypeBound())
)
or
exists(NodeExt mid, boolean allowsFieldFlow |
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
apf instanceof AccessPathFrontNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flowCand(mid, toReturn, apf, config)
)
or
exists(NodeExt mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/**
* A node that requires an empty access path and should have its tracked type
* (re-)computed. This is either a source or a node reached through an
* additional step.
*/
private class AccessPathNilNode extends NormalNodeExt {
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
/** Gets the `nil` path for this node. */
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
}
/**
* Holds if data can flow from a source to `node` with the given `ap`.
*/
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
flowCand(node, _, _, config) and
config.isSource(node.getNode()) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, unbind(config)) and
(
exists(NodeExt mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStepExt(mid, node, true, config)
localFlowBigStepExt(mid, node, true, _, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStepExt(mid, node, false, config) and
ap = node.(AccessPathNilNode).getAp() and
localFlowBigStepExt(mid, node, false, apf, config) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
flowFwd(mid, _, _, nil, config) and
additionalJumpStepExt(mid, node, config) and
fromArg = false and
ap = node.(AccessPathNilNode).getAp() and
ap = TNil(node.getErasedNodeTypeBound()) and
apf = ap.(AccessPathNil).getFront()
)
or
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
ap instanceof AccessPathNil
or
exists(NodeExt mid |
localFlowBigStepExt(node, mid, true, config) and
localFlowBigStepExt(node, mid, true, _, config) and
flow(mid, toReturn, ap, config)
)
or
exists(NodeExt mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStepExt(node, mid, false, config) and
localFlowBigStepExt(node, mid, false, _, config) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
localCC = getLocalCallContext(cc, enclosing)
|
localFlowBigStep(midnode, node, true, conf, localCC) and
localFlowBigStep(midnode, node, true, _, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
ap0 instanceof AccessPathNil
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
sc = mid.getSummaryCtx()
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
midnode = mid.getNode() and
cc = mid.getCallContext() and
conf = mid.getConfiguration() and
localFlowBigStep(midnode, _, _, conf, _) and
localFlowBigStep(midnode, _, _, _, conf, _) and
enclosing = midnode.getEnclosingCallable() and
sc = mid.getSummaryCtx() and
ap0 = mid.getAp()
@@ -2949,7 +2920,7 @@ private module FlowExploration {
config = mid.getConfiguration()
}
pragma[noinline]
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config

View File

@@ -50,7 +50,7 @@ module JsonNET {
) {
// ToString methods
c = getAToStringMethod() and
preservesValue = true and
preservesValue = false and
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
sink instanceof CallableFlowSinkReturn
or

View File

@@ -1,3 +1,275 @@
private import IR
import InstructionSanity
import IRTypeSanity
import InstructionSanity // module is below
import IRTypeSanity // module is in IRType.qll
module InstructionSanity {
private import internal.InstructionImports as Imports
private import Imports::OperandTag
private import internal.IRInternal
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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

@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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())
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.

View File

@@ -1,3 +1,275 @@
private import IR
import InstructionSanity
import IRTypeSanity
import InstructionSanity // module is below
import IRTypeSanity // module is in IRType.qll
module InstructionSanity {
private import internal.InstructionImports as Imports
private import Imports::OperandTag
private import internal.IRInternal
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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

@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
import Imports::Opcode
private import Imports::OperandTag
module InstructionSanity {
/**
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
*/
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
exists(OperandTag tag |
instr.getOpcode().hasOperand(tag) and
not exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
message =
"Instruction '" + instr.getOpcode().toString() +
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
*/
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
exists(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
not instr.getOpcode().hasOperand(tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
* Holds if instruction `instr` has multiple operands with tag `tag`.
*/
query predicate duplicateOperand(
Instruction instr, string message, IRFunction func, string funcText
) {
exists(OperandTag tag, int operandCount |
operandCount =
strictcount(NonPhiOperand operand |
operand = instr.getAnOperand() and
operand.getOperandTag() = tag
) and
operandCount > 1 and
not tag instanceof UnmodeledUseOperandTag and
message =
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
" in function '$@'." and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
)
}
/**
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
* the predecessor block `pred`.
*/
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
pred = instr.getBlock().getAPredecessor() and
not exists(PhiInputOperand operand |
operand = instr.getAnOperand() and
operand.getPredecessorBlock() = pred
)
}
query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func, Instruction use |
not exists(operand.getType()) and
use = operand.getUse() and
func = use.getEnclosingFunction() and
message =
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
"' missing type in function '" + Language::getIdentityString(func) + "'."
)
}
query predicate duplicateChiOperand(
ChiInstruction chi, string message, IRFunction func, string funcText
) {
chi.getTotal() = chi.getPartial() and
message =
"Chi instruction for " + chi.getPartial().toString() +
" has duplicate operands in function $@" and
func = chi.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
query predicate instructionWithoutSuccessor(Instruction instr) {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
* where `target` is among the targets of those edges.
*/
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
n > 1 and
source.getSuccessor(kind) = target
}
/**
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
* contains no element that can cause loops.
*/
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
exists(IRBlock block |
instr.getBlock() = block and
block.getEnclosingFunction() = f and
block.getASuccessor+() = block
) and
not Language::hasPotentialLoop(f)
}
/**
* Holds if a `Phi` instruction is present in a block with fewer than two
* predecessors.
*/
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
count(instr.getBlock().getAPredecessor()) < 2
}
/**
* Holds if operand `operand` consumes a value that was defined in
* a different function.
*/
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
operand.getUse() = instr and
operand.getAnyDef() = defInstr and
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
}
/**
* Holds if instruction `instr` is not in exactly one block.
*/
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
blockCount = count(instr.getBlock()) and
blockCount != 1
}
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
b1.getASuccessor() = b2 and
not b1.getBackEdgeSuccessor(_) = b2
}
/**
* Holds if `f` contains a loop in which no edge is a back edge.
*
* This check ensures we don't have too _few_ back edges.
*/
query predicate containsLoopOfForwardEdges(IRFunction f) {
exists(IRBlock block |
forwardEdge+(block, block) and
block.getEnclosingIRFunction() = f
)
}
/**
* Holds if `block` is reachable from its function entry point but would not
* be reachable by traversing only forward edges. This check is skipped for
* functions containing `goto` statements as the property does not generally
* hold there.
*
* This check ensures we don't have too _many_ back edges.
*/
query predicate lostReachability(IRBlock block) {
exists(IRFunction f, IRBlock entry |
entry = f.getEntryBlock() and
entry.getASuccessor+() = block and
not forwardEdge+(entry, block) and
not Language::hasGoto(f.getFunction())
)
}
/**
* Holds if the number of back edges differs between the `Instruction` graph
* and the `IRBlock` graph.
*/
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
fromInstr =
count(Instruction i1, Instruction i2 |
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
) and
fromBlock =
count(IRBlock b1, IRBlock b2 |
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
) and
fromInstr != fromBlock
}
/**
* Gets the point in the function at which the specified operand is evaluated. For most operands,
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
* of evaluation is at the end of the corresponding predecessor block.
*/
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
block = operand.(PhiInputOperand).getPredecessorBlock() and
index = block.getInstructionCount()
or
exists(Instruction use |
use = operand.(NonPhiOperand).getUse() and
block.getInstruction(index) = use
)
}
/**
* Holds if `useOperand` has a definition that does not dominate the use.
*/
query predicate useNotDominatedByDefinition(
Operand useOperand, string message, IRFunction func, string funcText
) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and
(
defInstr instanceof PhiInstruction and
defBlock = defInstr.getBlock() and
defIndex = -1
or
defBlock.getInstruction(defIndex) = defInstr
) and
not (
defBlock.strictlyDominates(useBlock)
or
defBlock = useBlock and
defIndex < useIndex
) and
message =
"Operand '" + useOperand.toString() +
"' is not dominated by its definition in function '$@'." and
func = useOperand.getEnclosingIRFunction() and
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())
}
}
/**
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
* `File` and line number. Used for assigning register names when printing IR.

View File

@@ -665,17 +665,18 @@ module DefUse {
private predicate definitionReachesRank(
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
) {
// The def always reaches the next use, even if there is also a def on the
// use instruction.
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
(
// The def always reaches the next use, even if there is also a def on the
// use instruction.
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
exists(int prevRank |
reachesRank = prevRank + 1 and
definitionReachesRank(useLocation, block, defRank, prevRank) and
not prevRank = exitRank(useLocation, block) and
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
)
}

View File

@@ -1381,7 +1381,7 @@
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1391,7 +1391,7 @@
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1401,7 +1401,7 @@
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1413,7 +1413,7 @@
| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z |
| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1421,7 +1421,7 @@
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1429,7 +1429,7 @@
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
@@ -1439,7 +1439,7 @@
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1449,7 +1449,7 @@
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1461,7 +1461,7 @@
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1473,7 +1473,7 @@
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1491,19 +1491,19 @@
| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
@@ -1521,7 +1521,7 @@
| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call |
| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1529,7 +1529,7 @@
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
@@ -1539,7 +1539,7 @@
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
@@ -1553,7 +1553,7 @@
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1569,7 +1569,7 @@
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
@@ -1583,7 +1583,7 @@
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1605,19 +1605,19 @@
| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) |
@@ -1627,7 +1627,7 @@
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
@@ -1641,7 +1641,7 @@
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1659,7 +1659,7 @@
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
@@ -1673,7 +1673,7 @@
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1685,7 +1685,7 @@
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
@@ -1699,7 +1699,7 @@
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1713,7 +1713,7 @@
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
@@ -1721,7 +1721,7 @@
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
@@ -1733,7 +1733,7 @@
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
@@ -1741,7 +1741,7 @@
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
@@ -1759,7 +1759,7 @@
| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:72 | call to method First |
@@ -1771,7 +1771,7 @@
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -1783,13 +1783,13 @@
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... |
| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] |
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... |
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] |
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] |
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) |
@@ -1799,7 +1799,7 @@
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
@@ -1807,7 +1807,7 @@
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
@@ -1835,7 +1835,7 @@
| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... |
| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
@@ -1843,7 +1843,7 @@
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
@@ -1859,7 +1859,7 @@
| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... |
| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] |
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... |
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] |
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] |
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... |
@@ -1873,13 +1873,13 @@
| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
@@ -1887,7 +1887,7 @@
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First |
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First : String |
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) |
@@ -1927,7 +1927,7 @@
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -2069,13 +2069,13 @@
| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... |
| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] |
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... |
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] |
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] |
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
@@ -2365,13 +2365,13 @@
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2383,13 +2383,13 @@
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2407,13 +2407,13 @@
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2423,13 +2423,13 @@
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2461,13 +2461,13 @@
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2477,13 +2477,13 @@
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2491,25 +2491,25 @@
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z |
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2537,21 +2537,21 @@
| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
@@ -2585,11 +2585,11 @@
| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable<String> | GlobalDataFlow.cs:114:76:114:76 | x |
@@ -2627,7 +2627,7 @@
| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:70 | call to method First |
@@ -2637,7 +2637,7 @@
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... |
@@ -2651,7 +2651,7 @@
| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... |
| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] |
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... |
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] |
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] |
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) |
@@ -2701,19 +2701,19 @@
| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... |
| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] |
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... |
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] |
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] |
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First |
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First : String |
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) |
@@ -3833,17 +3833,17 @@
| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink |
| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable<String> | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam |
@@ -3879,17 +3879,17 @@
| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink |
| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable<String> |
| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable<String> | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func<String,String> |

View File

@@ -137,21 +137,21 @@ edges
| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String |
| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String |
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String |
| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String |
@@ -199,7 +199,7 @@ edges
| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 |
| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 |
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 |
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 |
| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable<String> | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 |
| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String |
@@ -331,15 +331,15 @@ nodes
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | semmle.label | call to method SelectEven : IEnumerable<T> |
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | semmle.label | (...) ... : String[] |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | semmle.label | [output] delegate creation of type Func<String,String> : T |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 |
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | semmle.label | (...) ... : String[] |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | semmle.label | (...) ... : String[] |
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String |
| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | semmle.label | access to local variable sink14 : IEnumerable<String> |
@@ -404,7 +404,7 @@ nodes
| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 |
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String |
| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 |
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> | semmle.label | sinkParam8 : IEnumerable<String> |
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] |
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 |
| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | semmle.label | sinkParam9 : String |
| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 |

View File

@@ -1,41 +1,7 @@
# Experimental CodeQL queries and libraries
In addition to our standard CodeQL queries and libraries, this repository may also contain queries and libraries of a more experimental nature. Experimental queries and libraries can be improved incrementally and may eventually reach a sufficient maturity to be included in our standard libraries and queries.
In addition to [our supported queries and libraries](supported-queries.md), this repository also contains queries and libraries of a more experimental nature. Experimental queries and libraries can be improved incrementally and may eventually reach a sufficient maturity to be included in our supported queries and libraries.
Experimental queries and libraries may not be actively maintained as the standard libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings.
Experimental queries and libraries may not be actively maintained as the [supported](supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings.
## Requirements
1. **Directory structure**
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/Semmle/ql). For example, experimental Java queries and libraries are stored in `ql/java/ql/src/experimental` and any corresponding tests in `ql/java/ql/test/experimental`.
- The structure of an `experimental` subdirectory mirrors the structure of standard queries and libraries (or tests) in the parent directory.
2. **Query metadata**
- The query `@id` must not clash with any other queries in the repository.
- The query must have a `@name` and `@description` to explain its purpose.
- The query must have a `@kind` and `@problem.severity` as required by CodeQL tools.
For details, see the [guide on query metadata](https://github.com/Semmle/ql/blob/master/docs/query-metadata-style-guide.md).
3. **Formatting**
- The queries and libraries must be [autoformatted](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting).
4. **Compilation**
- Compilation of the query and any associated libraries and tests must be resilient to future development of the standard libraries. This means that the functionality cannot use internal APIs, cannot depend on the output of `getAQlClass`, and cannot make use of regexp matching on `toString`.
- The query and any associated libraries and tests must not cause any compiler warnings to be emitted (such as use of deprecated functionality or missing `override` annotations).
5. **Results**
- The query must have at least one true positive result on some revision of a real project.
6. **Contributor License Agreement**
- The contributor can satisfy the [CLA](CONTRIBUTING.md#contributor-license-agreement).
## Non-requirements
Other criteria typically required for our standard queries and libraries are not required for experimental queries and libraries. In particular, fully disciplined query [metadata](docs/query-metadata-style-guide.md), query [help](docs/query-help-style-guide.md), tests, a low false positive rate and performance tuning are not required (but nonetheless recommended).
See [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines on submitting a new experimental query.

View File

@@ -34,7 +34,7 @@
<div id="siteBanner">
<div class="textContainer">
<div class="logocontainer">
<a href="https://semmle.com/" id="Header-logo" class="">
<a href="https://help.semmle.com/" id="Header-logo" class="">
<svg class="Header-logo-white" width="98" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="a" d="M0 .149h12.872v18.814H0z"></path>
@@ -102,7 +102,7 @@
{{super()}}
</div>
<div class="privacy">
<a target="_blank" href="https://semmle.com/privacy-policy" alt="Privacy policy and tracking preferences" title="Privacy policy and tracking preferences">Privacy policy</a>
<a target="_blank" href="https://help.semmle.com/privacy-policy.html" alt="Privacy policy and tracking preferences" title="Privacy policy and tracking preferences">Privacy policy</a>
</div>
</div>

View File

@@ -61,7 +61,7 @@ These topics are discussed in detail in the `QL language handbook <https://help.
References
----------
Academic references available from the `Semmle website <https://semmle.com/publications>`__ also provide an overview of QL and its semantics. Other useful references on database query languages and Datalog:
Academic references available from the `Semmle website <https://help.semmle.com/publications.html>`__ also provide an overview of QL and its semantics. Other useful references on database query languages and Datalog:
- `Database theory: Query languages <http://www.lsv.ens-cachan.fr/~segoufin/Papers/Mypapers/DB-chapter.pdf>`__
- `Logic Programming and Databases book - Amazon page <http://www.amazon.co.uk/Programming-Databases-Surveys-Computer-Science/dp/3642839541>`__

View File

@@ -1,151 +0,0 @@
Introducing the CodeQL libraries for COBOL
==========================================
Overview
--------
There is an extensive library for analyzing COBOL code. The classes in this library present the data from a CodeQL database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks.
The library is implemented as a set of QL modulesthat is, files with the extension ``.qll``. The module ``cobol.qll`` imports most other standard library modules, so you can include the complete library by beginning your query with:
.. code-block:: ql
import cobol
The rest of this tutorial briefly summarizes the most important classes and predicates provided by this library, including references to the `detailed API documentation <https://help.semmle.com/qldoc/cobol/>`__ where applicable.
Introducing the library
-----------------------
The CodeQL library for COBOL presents information about COBOL source code at different levels:
- **Textual** — classes that represent source code as unstructured text files
- **Lexical** — classes that represent comments and other tokens of interest
- **Syntactic** — classes that represent source code as an abstract syntax tree
- **Name binding** — classes that represent data entries and data references
- **Control flow** — classes that represent the flow of control during execution
- **Frameworks** — classes that represent interactions via CICS and SQL
Note that representations above the textual level (for example the lexical representation or the flow graphs) are only available for COBOL code that does not contain fatal syntax errors. For code with such errors, the only information available is at the textual level, as well as information about the errors themselves.
Textual level
~~~~~~~~~~~~~
At its most basic level, a COBOL code base can simply be viewed as a collection of files organized into folders.
Files and folders
^^^^^^^^^^^^^^^^^
Files are represented as entities of class `File <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$File.html>`__, and folders as entities of class `Folder <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Folder.html>`__, both of which are subclasses of class `Container <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Container.html>`__.
Class `Container <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Container.html>`__ provides the following member predicates:
- ``Container.getParentContainer()`` returns the parent folder of the file or folder.
- ``Container.getAFile()`` returns a file within the folder.
- ``Container.getAFolder()`` returns a folder nested within the folder.
Note that while ``getAFile`` and ``getAFolder`` are declared on class `Container <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Container.html>`__, they currently only have results for `Folder <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Folder.html>`__\ s.
Both files and folders have paths, which can be accessed by the predicate ``Container.getAbsolutePath()``. For example, if ``f`` represents a file with the path ``/home/user/project/src/main.cbl``, then ``f.getAbsolutePath()`` evaluates to the string ``"/home/user/project/src/main.cbl"``, while ``f.getParentContainer().getAbsolutePath()`` returns ``"/home/user/project/src"``.
These paths are absolute file system paths. If you want to obtain the path of a file relative to the source location in the CodeQL database, use ``Container.getRelativePath()`` instead. Note, however, that a database may contain files that are not located underneath the source location; for such files, ``getRelativePath()`` will not return anything.
The following member predicates of class `Container <https://help.semmle.com/qldoc/cobol/semmle/cobol/Files.qll/type.Files$Container.html>`__ provide more information about the name of a file or folder:
- ``Container.getBaseName()`` returns the base name of a file or folder, not including its parent folder, but including its extension. In the above example, ``f.getBaseName()`` would return the string ``"main.cbl"``.
- ``Container.getStem()`` is similar to ``Container.getBaseName()``, but it does *not* include the file extension; so ``f.getStem()`` returns ``"main"``.
- ``Container.getExtension()`` returns the file extension, not including the dot; so ``f.getExtension()`` returns ``"cbl"``.
For example, the following query computes, for each folder, the number of COBOL files (that is, files with extension ``cbl``) contained in the folder:
.. code-block:: ql
import cobol
from Folder d
select d.getRelativePath(), count(File f | f = d.getAFile() and f.getExtension() = "cbl")
Locations
^^^^^^^^^
Most entities in a CodeQL database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive.
All entities associated with a source location belong to the class `Locatable <https://help.semmle.com/qldoc/cobol/semmle/cobol/Location.qll/type.Location$Locatable.html>`__. The location itself is modeled by the class `Location <https://help.semmle.com/qldoc/cobol/semmle/cobol/Location.qll/type.Location$Location.html>`__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location <https://help.semmle.com/qldoc/cobol/semmle/cobol/Location.qll/type.Location$Location.html>`__ class provides the following member predicates:
- ``Location.getFile()``, ``Location.getStartLine()``, ``Location.getStartColumn()``, ``Location.getEndLine()``, ``Location.getEndColumn()`` return detailed information about the location.
- ``Location.getNumLines()`` returns the number of (whole or partial) lines covered by the location.
- ``Location.startsBefore(Location)`` and ``Location.endsAfter(Location)`` determine whether one location starts before or ends after another location.
- ``Location.contains(Location)`` indicates whether one location completely contains another location; ``l1.contains(l2)`` holds if, and only if, ``l1.startsBefore(l2)`` and ``l1.endsAfter(l2)``.
Lexical level
~~~~~~~~~~~~~
At this level we represent comments through the `Comment <https://help.semmle.com/qldoc/cobol/semmle/cobol/Comments.qll/type.Comments$Comment.html>`__ class. We do not currently retain any tokens other than scope terminators (for example ``END-IF``), which are represented by the `ScopeTerminator <https://help.semmle.com/qldoc/cobol/semmle/cobol/Stmts.qll/type.Stmts$ScopeTerminator.html>`__ class.
Comments
^^^^^^^^
The class `Comment <https://help.semmle.com/qldoc/cobol/semmle/cobol/Comments.qll/type.Comments$Comment.html>`__ represents the comments that occur in COBOL programs:
The most important member predicates are as follows:
- ``Comment.getText()`` returns the source text of the comment, not including delimiters.
- ``Comment.getScope()`` returns the location of the source code to which the comment is bound.
Scope terminators
^^^^^^^^^^^^^^^^^
The class `ScopeTerminator <https://help.semmle.com/qldoc/cobol/semmle/cobol/Stmts.qll/type.Stmts$ScopeTerminator.html>`__ represents the scope terminators that occur in COBOL programs:
The most important member predicates are as follows:
- ``ScopeTerminator.getStmt()`` returns the statement whose scope this terminator is closing.
Syntactic level
~~~~~~~~~~~~~~~
The majority of classes in the CodeQL library for COBOL are concerned with representing a COBOL program as a collection of `abstract syntax trees <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`__ (ASTs).
The class `ASTNode <https://help.semmle.com/qldoc/cobol/semmle/cobol/AstNode.qll/type.AstNode$AstNode.html>`__ contains all entities representing nodes in the abstract syntax trees and defines generic tree traversal predicates:
- ``ASTNode.getParent()``: returns the parent node of this AST node, if any.
Please note that the libraries for COBOL do not currently represent all possible parts of a COBOL program. Due to the complexity of the language, and its many dialects, this is an ongoing task. We prioritize elements that are of interest to queries, and expand this selection over time. Please check the `detailed API documentation <https://help.semmle.com/qldoc/cobol/>`__ to see what is currently available.
The main structure of any COBOL program is represented by the `Unit <https://help.semmle.com/qldoc/cobol/semmle/cobol/Units.qll/type.Units$Unit.html>`__ class and its subclasses. For example, each program definition has a `ProgramDefinition <https://help.semmle.com/qldoc/cobol/semmle/cobol/Units.qll/type.Units$ProgramDefinition.html>`__ counterpart. For each ``PROCEDURE DIVISION`` in the program, there will be a `ProcedureDivision <https://help.semmle.com/qldoc/cobol/semmle/cobol/AST_extended.qll/type.AST_extended$ProcedureDivision.html>`__ class.
All data definitions are made accessible through the `DescriptionEntry <https://help.semmle.com/qldoc/cobol/semmle/cobol/DataEntries.qll/type.DataEntries$DescriptionEntry.html>`__ class and its subclasses. In particular, you can use `DataDescriptionEntry <https://help.semmle.com/qldoc/cobol/semmle/cobol/DataEntries.qll/type.DataEntries$DataDescriptionEntry.html>`__ to find the typical data entries defined in a ``WORKING-STORAGE SECTION``.
References to data items are modeled through the `DataReference <https://help.semmle.com/qldoc/cobol/semmle/cobol/References.qll/type.References$DataReference.html>`__ class. You can use ``DataReference.getTarget()`` to resolve the reference to the matching data item.
Individual statements are represented by the class `Stmt <https://help.semmle.com/qldoc/cobol/semmle/cobol/Stmts.qll/type.Stmts$Stmt.html>`__ and its subclasses. The name of the specific type starts with the statement's verb. For example, ``OPEN`` statements are covered by the class `Open <https://help.semmle.com/qldoc/cobol/semmle/cobol/Stmts.qll/type.Stmts$Open.html>`__. Unknown statement types are covered by the
`OtherStmt <https://help.semmle.com/qldoc/cobol/semmle/cobol/AST_extended.qll/type.AST_extended$OtherStmt.html>`__ class.
Control flow
~~~~~~~~~~~~
You can represent a program in terms of its control flow graph (CFG) using the ``AstNode.getASuccessor`` predicate. You can use this predicate to find possible successors to any statement, sentence, or unit in a procedure division.
Parse errors
~~~~~~~~~~~~~
COBOL code that contains breaking syntax errors cannot usually be analyzed. All that is available in this case is a value of class `Error <https://help.semmle.com/qldoc/cobol/semmle/cobol/Errors.qll/type.Errors$Error.html>`__ representing the parse error. It provides information about the syntax error location and the error message through predicates ``Error.getLocation`` and ``Error.getMessage`` respectively.
Frameworks
~~~~~~~~~~
CICS
^^^^
Calls to the CICS system through ``EXEC CICS`` are represented by the class `CICS <https://help.semmle.com/qldoc/cobol/semmle/cobol/AST_extended.qll/type.AST_extended$Cics.html>`__.
SQL
^^^
Calls to the SQL system through ``EXEC SQL`` are represented by the class
`SqlStmt <https://help.semmle.com/qldoc/cobol/semmle/cobol/Sql.qll/type.Sql$SqlStmt.html>`__ and its subclasses.
What next?
----------
- Find out more about QL in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__ and `QL language specification <https://help.semmle.com/QL/ql-spec/language.html>`__.

View File

@@ -1,20 +0,0 @@
CodeQL for COBOL
================
.. toctree::
:glob:
:hidden:
introduce-libraries-cobol
.. include:: ../../support/cobol-note.rst
This page provides an overview of the CodeQL for COBOL documentation that is currently available.
- :doc:`Introducing the CodeQL libraries for COBOL <introduce-libraries-cobol>` introduces the standard libraries used to write queries for COBOL code.
Other resources
---------------
- For more information about the library for COBOL see the `CodeQL library for COBOL <https://help.semmle.com/qldoc/cobol/>`__.

View File

@@ -1,7 +1,7 @@
Learning CodeQL
###############
CodeQL is the code analysis platform used by security researchers to automate `variant analysis <https://semmle.com/variant-analysis>`__.
CodeQL is the code analysis platform used by security researchers to automate variant analysis.
You can use CodeQL queries to explore code and quickly find variants of security vulnerabilities and bugs.
These queries are easy to write and sharevisit the topics below and `our open source repository on GitHub <https://github.com/Semmle/ql>`__ to learn more.
You can also try out CodeQL in the `query console <https://lgtm.com/query>`__ on `LGTM.com <https://lgtm.com>`__.
@@ -67,7 +67,6 @@ For more information on using CodeQL to query code written in a specific languag
cpp/ql-for-cpp
csharp/ql-for-csharp
cobol/ql-for-cobol
go/ql-for-go
java/ql-for-java
javascript/ql-for-javascript

View File

@@ -4,9 +4,9 @@ CodeQL training and variant analysis examples
CodeQL and variant analysis
---------------------------
`Variant analysis <https://semmle.com/variant-analysis>`__ is the process of using a known vulnerability as a seed to find similar problems in your code. Security engineers typically perform variant analysis to identify possible vulnerabilities and to ensure that these threats are properly fixed across multiple code bases.
Variant analysis is the process of using a known vulnerability as a seed to find similar problems in your code. Security engineers typically perform variant analysis to identify possible vulnerabilities and to ensure that these threats are properly fixed across multiple code bases.
`CodeQL <https://semmle.com/ql>`__ is the code analysis engine that underpins LGTM, Semmle's community driven security analysis platform. Together, CodeQL and LGTM provide continuous monitoring and scalable variant analysis for your projects, even if you dont have your own team of dedicated security engineers. You can read more about using CodeQL and LGTM in variant analysis on the `Security Lab research page <https://securitylab.github.com/research>`__.
CodeQL is the code analysis engine that underpins LGTM, the community driven security analysis platform. Together, CodeQL and LGTM provide continuous monitoring and scalable variant analysis for your projects, even if you dont have your own team of dedicated security engineers. You can read more about using CodeQL and LGTM in variant analysis on the `Security Lab research page <https://securitylab.github.com/research>`__.
CodeQL is easy to learn, and exploring code using CodeQL is the most efficient way to perform variant analysis.

View File

@@ -78,7 +78,7 @@ When writing your own alert queries, you would typically import the standard lib
- C/C++: ``cpp``
- C#: ``csharp``
- COBOL: ``cobol``
- Go: ``go``
- Java: ``java``
- JavaScript/TypeScript: ``javascript``
- Python: ``python``
@@ -140,4 +140,4 @@ What next?
- To learn more about writing path queries, see :doc:`Constructing path queries <path-queries>`.
- Take a look at the `built-in queries <https://help.semmle.com/wiki/display/QL/Built-in+queries>`__ to see examples of the queries included in CodeQL.
- Explore the `query cookbooks <https://help.semmle.com/wiki/display/QL/QL+cookbooks>`__ to see how to access the basic language elements contained in the CodeQL libraries.
- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL <https://help.semmle.com/QL/learn-ql/>`__.
- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL <https://help.semmle.com/QL/learn-ql/>`__.

View File

@@ -141,7 +141,7 @@ Lets look for overflow guards of the form ``v + b < v``, using the classes
.. note::
- When performing `variant analysis <https://semmle.com/variant-analysis>`__, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- In this case, we start by looking for all the *overflow* checks, before trying to refine the query to find all *bad overflow* checks.
- The ``select`` clause defines what this query is looking for:

View File

@@ -77,7 +77,7 @@ Lets start by looking for calls to methods with names of the form ``sparql*Qu
.. note::
- When performing `variant analysis <https://semmle.com/variant-analysis>`__, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- In this case, we start by looking for all the method calls that appear to run, before trying to refine the query to find cases which are vulnerable to query injection.
- The ``select`` clause defines what this query is looking for:

View File

@@ -81,8 +81,6 @@ Find all instances!
- All were fixed with a mid-flight patch.
- For more detail on the collaboration between Semmle and NASA, see our case study: `Semmle at NASA: Landing Curiosity safely on Mars <https://semmle.com/case-studies/semmle-nasa-landing-curiosity-safely-mars>`__.
.. note::
The JPL team ran the query across the full Curiosity control softwareit identified the original problem, and more than 30 other variants, of which three were in the critical Entry, Descent, and Landing module.
@@ -107,7 +105,7 @@ Analysis overview
Once the extraction finishes, all this information is collected into a single `CodeQL database <https://help.semmle.com/QL/learn-ql/database.html>`__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific.
Queries are written in `QL <https://semmle.com/ql>`__ and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developers machine.
Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developers machine.
Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE extension <https://lgtm.com/help/lgtm/running-queries-ide>`__ such as CodeQL for Visual Studio Code, or in a web dashboard as on `LGTM <https://lgtm.com/help/lgtm/about-lgtm>`__.

View File

@@ -1,5 +0,0 @@
.. pull-quote:: Important
CodeQL for COBOL is being deprecated after the 1.23 release of CodeQL.
Future releases, starting with 1.24, will no longer contain support for analyzing COBOL source code.
We are not aware of any customers who will be affected by this change. If you do have any concerns, please contact your account manager.

View File

@@ -80,4 +80,4 @@ htmlhelp_basename = 'Supported languages and frameworks'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['read-me-project.rst', 'cobol-note.rst']
exclude_patterns = ['read-me-project.rst']

View File

@@ -10,8 +10,6 @@ Customers with any questions should contact their usual Semmle contact with any
If you're not a customer yet, contact us at info@semmle.com
with any questions you have about language and compiler support.
.. include:: cobol-note.rst
.. csv-table::
:file: versions-compilers.csv
:header-rows: 1

View File

@@ -1,11 +1,11 @@
Language,Variants,Compilers,Extensions
C/C++,"C89, C99, C11, C++98, C++03, C++11, C++14, C++17","Clang (and clang-cl [1]_) extensions (up to Clang 8.0),
C/C++,"C89, C99, C11, C18, C++98, C++03, C++11, C++14, C++17","Clang (and clang-cl [1]_) extensions (up to Clang 9.0),
GNU extensions (up to GCC 8.3),
GNU extensions (up to GCC 9.2),
Microsoft extensions (up to VS 2019),
Arm Compiler 5.0 [2]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
Arm Compiler 5 [2]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
C#,C# up to 8.0. with .NET up to 4.8 [3]_,"Microsoft Visual Studio up to 2019,
.NET Core up to 3.0","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
1 Language Variants Compilers Extensions
2 C/C++ C89, C99, C11, C++98, C++03, C++11, C++14, C++17 C89, C99, C11, C18, C++98, C++03, C++11, C++14, C++17 Clang (and clang-cl [1]_) extensions (up to Clang 8.0), GNU extensions (up to GCC 8.3), Microsoft extensions (up to VS 2019), Arm Compiler 5.0 [2]_ Clang (and clang-cl [1]_) extensions (up to Clang 9.0), GNU extensions (up to GCC 9.2), Microsoft extensions (up to VS 2019), Arm Compiler 5 [2]_ ``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``
3 C# C# up to 8.0. with .NET up to 4.8 [3]_ Microsoft Visual Studio up to 2019, .NET Core up to 3.0 ``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``
4 Go (aka Golang) Go up to 1.13 Go 1.11 or more recent ``.go``
5 Java Java 6 to 13 [4]_ javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_ ``.java``
6 JavaScript ECMAScript 2019 or lower Not applicable ``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_
7 Python 2.7, 3.5, 3.6, 3.7, 3.8 Not applicable ``.py``
8 TypeScript [7]_ 2.6-3.7 Standard TypeScript compiler ``.ts``, ``.tsx``
9
10
11

View File

@@ -2,7 +2,7 @@
## Introduction
This document outlines the structure of Semmle query files. You should adopt this structure when contributing custom queries to this repository, in order to ensure that new queries are consistent with the standard Semmle queries.
This document outlines the structure of CodeQL query files. You should adopt this structure when contributing custom queries to this repository, in order to ensure that new queries are consistent with the standard CodeQL queries.
## Query files (.ql extension)
@@ -67,11 +67,11 @@ You must define an `@description` property for your query. This property defines
### Query ID `@id`
You must specify an `@id` property for your query. It must be unique in the Semmle namespace and should follow the standard Semmle convention. That is, it should begin with the 'language code' for the language that the query analyzes followed by a forward slash. The following language codes are supported:
You must specify an `@id` property for your query. It must be unique and should follow the standard CodeQL convention. That is, it should begin with the 'language code' for the language that the query analyzes followed by a forward slash. The following language codes are supported:
* C and C++: `cpp`
* C#: `cs`
* COBOL: `cobol`
* Go: `go`
* Java: `java`
* JavaScript and TypeScript: `js`
* Python: `py`
@@ -105,7 +105,7 @@ Note, `@id` properties should be consistent for queries that highlight the same
* alerts (`@kind problem`)
* alerts containing path information (`@kind path-problem`)
Alert queries (`@kind problem` or `path-problem`) support two further properties. These are added by Semmle after the query has been tested, prior to deployment to LGTM. The following information is for reference:
Alert queries (`@kind problem` or `path-problem`) support two further properties. These are added by GitHub staff after the query has been tested, prior to deployment to LGTM. The following information is for reference:

79
docs/supported-queries.md Normal file
View File

@@ -0,0 +1,79 @@
# Supported CodeQL queries and libraries
Queries and libraries outside [the `experimental` directories](experimental.md) are _supported_ by GitHub, allowing our users to rely on their continued existence and functionality in the future:
1. Once a query or library has appeared in a stable release, a one-year deprecation period is required before we can remove it. There can be exceptions to this when it's not technically possible to mark it as deprecated.
2. Major changes to supported queries and libraries are always announced in the [change notes for stable releases](../change-notes/).
3. We will do our best to address user reports of false positives or false negatives.
Because of these commitments, we set a high bar for accepting new supported queries. The requirements are detailed in the rest of this document.
## Steps for introducing a new supported query
The process must begin with the first step and must conclude with the final step. The remaining steps can be performed in any order.
1. **Have the query merged into the appropriate `experimental` subdirectory**
See [CONTRIBUTING.md](../CONTRIBUTING.md).
2. **Write a query help file**
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 query. For more information on writing query help, see the [Query help style guide](query-help-style-guide.md).
- Note, in particular, that almost all queries need to have a pair of "before" and "after" examples demonstrating the kind of problem the query identifies and how to fix it. Make sure that the examples are actually consistent with what the query does, for example by including them in your unit tests.
- At the time of writing, there is no way of previewing help locally. Once you've opened a PR, a preview will be created as part of the CI checks. A GitHub employee will review this and let you know of any problems.
3. **Write unit tests**
Add one or more unit tests for the query (and for any library changes you make) to the `ql/<language>/ql/test/experimental` directory. Tests for library changes go into the `library-tests` subdirectory, and tests for queries go into `query-tests` with their relative path mirroring the query's location under `ql/<language>/ql/src/experimental`.
See the section on [Testing custom queries](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) in the [CodeQL documentation](https://help.semmle.com/codeql/) for more information.
4. **Test for correctness on real-world code**
Test the query on a number of large real-world projects to make sure it doesn't give too many false positive results. Adjust the `@precision` and `@problem.severity` attributes in accordance with the real-world results you observe. See the advice on query metadata below.
You can use the LGTM.com [query console](https://lgtm.com/query) to get an overview of true and false positive results on a large number of projects. The simplest way to do this is to:
1. [Create a list of prominent projects](https://lgtm.com/help/lgtm/managing-project-lists) on LGTM.
2. In the query console, [run your query against your custom project list](https://lgtm.com/help/lgtm/using-query-console).
3. Save links to your query console results and include them in discussions on issues and pull requests.
5. **Test and improve performance**
There must be a balance between the execution time of a query and the value of its results: queries that are highly valuable and broadly applicable can be allowed to take longer to run. In all cases, you need to address any easy-to-fix performance issues before the query is put into production.
QL performance profiling and tuning is an advanced topic, and some tasks will require assistance from GitHub employees. With that said, there are several things you can do.
- Understand [the evaluation model of QL](https://help.semmle.com/QL/ql-handbook/evaluation.html). It's more similar to SQL than to any mainstream programming language.
- Most performance tuning in QL boils down to computing as few tuples (rows of data) as possible. As a mental model, think of predicate evaluation as enumerating all combinations of parameters that satisfy the predicate body. This includes the implicit parameters `this` and `result`.
- The major libraries in CodeQL are _cached_ and will only be computed once for the entire suite of queries. The first query that needs a cached _stage_ will trigger its evaluation. This means that query authors should usually only look at the run time of the last stage of evaluation.
- In [the settings for the VSCode extension](https://help.semmle.com/codeql/codeql-for-vscode/reference/settings.html), check the box "Running Queries: Debug" (`codeQL.runningQueries.debug`). Then find "CodeQL Query Server" in the VSCode Output panel (View -> Output) and capture the output when running the query. That output contains timing and tuple counts for all computed predicates.
- To clear the entire cache, invoke "CodeQL: Clear Cache" from the VSCode command palette.
6. **Make sure your query has the correct metadata**
For the full reference on writing query metadata, see the [Query metadata style guide](query-metadata-style-guide.md). The following constitutes a checklist.
a. Each query needs a `@name`, a `@description`, and a `@kind`.
b. Alert queries also need a `@problem.severity` and a `@precision`.
- The severity is one of `error`, `warning`, or `recommendation`.
- The precision is one of `very-high`, `high`, `medium` or `low`. It may take a few iterations to get this right.
- Currently, LGTM runs all `error` or `warning` queries with a `very-high`, `high`, or `medium` precision. In addition, `recommendation` queries with `very-high` or `high` precision are run.
- However, results from `error` and `warning` queries with `medium` precision, as well as `recommendation` queries with `high` precision, are not shown by default.
c. All queries need an `@id`.
- The ID should be consistent with the ids of similar queries for other languages; for example, there is a C/C++ query looking for comments containing the word "TODO" which has id `cpp/todo-comment`, and its C# counterpart has id `cs/todo-comment`.
d. Provide one or more `@tags` describing the query.
- Tags are free-form, but we have some conventions, especially for tagging security queries with corresponding CWE numbers.
7. **Move your query out of `experimental`**
- The structure of an `experimental` subdirectory mirrors the structure of its parent directory, so this step may just be a matter of removing the `experimental/` prefix of the query and test paths. Be sure to also edit any references to the query path in tests.
- Add the query to one of the legacy suite files in `ql/<language>/config/suites/<language>/` if it exists. Note that there are separate suite directories for C and C++, `c` and `cpp` respectively, and the query should be added to one or both as appropriate.
- Add a release note to `change-notes/<next-version>/analysis-<language>.md`.

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